Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 307919a..251620c 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -87,9 +87,15 @@
     private static int nextFlowEntryIdSuffix = 0;
     private static long nextFlowEntryId = 0;
 
+    // State for measurement purpose
     private static long measurementFlowId = 100000;
     private static String measurementFlowIdStr = "0x186a0";	// 100000
     private long modifiedMeasurementFlowTime = 0;
+    //
+    private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
+    private LinkedList<FlowPath> measurementProcessingPaths = null;
+    private long measurementStartTimeProcessingPaths = 0;
+    private long measurementEndTimeProcessingPaths = 0;
 
     /** The logger. */
     private static Logger log = LoggerFactory.getLogger(FlowManager.class);
@@ -462,7 +468,7 @@
 		shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
     }
 
-    private long getNextFlowEntryId() {
+    private synchronized long getNextFlowEntryId() {
 	//
 	// Generate the next Flow Entry ID.
 	// NOTE: For now, the higher 32 bits are random, and
@@ -745,6 +751,23 @@
     }
 
     /**
+     * Delete all previously added flows.
+     *
+     * @return true on success, otherwise false.
+     */
+    @Override
+    public boolean deleteAllFlows() {
+
+	// Get all flows and delete them one-by-one
+    	ArrayList<FlowPath> allFlows = getAllFlows();
+	for (FlowPath flowPath : allFlows) {
+	    deleteFlow(flowPath.flowId());
+	}
+
+	return true;
+    }
+
+    /**
      * Delete a previously added flow.
      *
      * @param flowId the Flow ID of the flow to delete.
@@ -807,6 +830,23 @@
     }
 
     /**
+     * Clear the state for all previously added flows.
+     *
+     * @return true on success, otherwise false.
+     */
+    @Override
+    public boolean clearAllFlows() {
+
+	// Get all flows and clear them one-by-one
+    	ArrayList<FlowPath> allFlows = getAllFlows();
+	for (FlowPath flowPath : allFlows) {
+	    clearFlow(flowPath.flowId());
+	}
+
+	return true;
+    }
+
+    /**
      * Clear the state for a previously added flow.
      *
      * @param flowId the Flow ID of the flow to clear.
@@ -1763,4 +1803,178 @@
 	//
 	return (installRemoteFlowEntry(flowPath, flowEntry));
     }
+
+    /**
+     * Store a path flow for measurement purpose.
+     *
+     * NOTE: The Flow Path argument does NOT contain flow entries.
+     * The Shortest Path is computed, and the corresponding Flow Entries
+     * are stored in the Flow Path.
+     *
+     * @param flowPath the Flow Path with the endpoints and the match
+     * conditions to store.
+     * @return the stored shortest-path flow on success, otherwise null.
+     */
+    @Override
+    public FlowPath measurementStorePathFlow(FlowPath flowPath) {
+	//
+	// Prepare the Shortest Path computation if the first Flow Path
+	//
+	if (measurementStoredPaths.isEmpty())
+	    topoRouteService.prepareShortestPathTopo();
+
+	//
+	// Compute the Shortest Path
+	//
+	DataPath dataPath =
+	    topoRouteService.getTopoShortestPath(flowPath.dataPath().srcPort(),
+						 flowPath.dataPath().dstPort());
+	if (dataPath == null) {
+	    // We need the DataPath to populate the Network MAP
+	    dataPath = new DataPath();
+	    dataPath.setSrcPort(flowPath.dataPath().srcPort());
+	    dataPath.setDstPort(flowPath.dataPath().dstPort());
+	}
+
+	//
+	// Set the incoming port matching and the outgoing port output
+	// actions for each flow entry.
+	//
+	for (FlowEntry flowEntry : dataPath.flowEntries()) {
+	    // Set the incoming port matching
+	    FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
+	    flowEntry.setFlowEntryMatch(flowEntryMatch);
+	    flowEntryMatch.enableInPort(flowEntry.inPort());
+
+	    // Set the outgoing port output action
+	    ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
+	    if (flowEntryActions == null) {
+		flowEntryActions = new ArrayList<FlowEntryAction>();
+		flowEntry.setFlowEntryActions(flowEntryActions);
+	    }
+	    FlowEntryAction flowEntryAction = new FlowEntryAction();
+	    flowEntryAction.setActionOutput(flowEntry.outPort());
+	    flowEntryActions.add(flowEntryAction);
+	}
+
+	//
+	// Prepare the computed Flow Path
+	//
+	FlowPath computedFlowPath = new FlowPath();
+	computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
+	computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
+	computedFlowPath.setDataPath(dataPath);
+	computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
+
+	//
+	// Add the computed Flow Path the the internal storage
+	//
+	measurementStoredPaths.add(computedFlowPath);
+
+	return (computedFlowPath);
+    }
+
+    /**
+     * Install path flows for measurement purpose.
+     *
+     * @param numThreads the number of threads to use to install the path
+     * flows.
+     * @return true on success, otherwise false.
+     */
+    @Override
+    public boolean measurementInstallPaths(Integer numThreads) {
+	List<Thread> threads = new LinkedList<Thread>();
+
+	// Create a copy of the paths to install
+	measurementProcessingPaths = new LinkedList<FlowPath>(measurementStoredPaths);
+
+	//
+	// Create the threads to install the Flow Paths
+	//
+	for (int i = 0; i < numThreads; i++) {
+	    Thread thread = new Thread(new Runnable() {
+		@Override
+		public void run() {
+		    while (true) {
+			FlowPath flowPath = measurementPollFirstFlowPath();
+			if (flowPath == null)
+			    return;
+			// Install the Flow Path
+			FlowId flowId = new FlowId();
+			String dataPathSummaryStr =
+			    flowPath.dataPath().dataPathSummary();
+			addFlow(flowPath, flowId, dataPathSummaryStr);
+		    }
+		}}, "Measurement Add Flow Path");
+	    threads.add(thread);
+	}
+
+	//
+	// Start processing
+	//
+	measurementEndTimeProcessingPaths = 0;
+	measurementStartTimeProcessingPaths = System.nanoTime();
+	for (Thread thread : threads) {
+	    thread.start();
+	}
+
+	//
+	// Wait until the end of processing time
+	//
+	while (measurementEndTimeProcessingPaths == 0) {
+	    try {
+		Thread.sleep(100);
+	    } catch (InterruptedException e) {
+		// Continue waiting
+	    }
+	}
+
+	return true;
+    }
+
+    /**
+     * Get the measurement time that took to install the path flows.
+     *
+     * @return the measurement time (in nanoseconds) it took to install
+     * the path flows.
+     */
+    @Override
+    public Long measurementGetInstallPathsTimeNsec() {
+	return new Long(measurementEndTimeProcessingPaths -
+			measurementStartTimeProcessingPaths);
+    }
+
+    /**
+     * Get a Flow Path that needs to be installed for measurement purpose.
+     *
+     * If there is no next Flow Path to install, the end time measurement
+     * is recorded.
+     *
+     * @return the next Flow Path to install if exists, otherwise null.
+     */
+    private synchronized FlowPath measurementPollFirstFlowPath() {
+	FlowPath flowPath = measurementProcessingPaths.pollFirst();
+
+	// Record the end of processing, if the first call
+	if ((flowPath == null) && (measurementEndTimeProcessingPaths == 0))
+	    measurementEndTimeProcessingPaths = System.nanoTime();
+
+	return flowPath;
+    }
+
+    /**
+     * Clear the path flows stored for measurement purpose.
+     *
+     * @return true on success, otherwise false.
+     */
+    @Override
+    public boolean measurementClearAllPaths() {
+	measurementStoredPaths.clear();
+	topoRouteService.dropShortestPathTopo();
+	measurementStartTimeProcessingPaths = 0;
+	measurementEndTimeProcessingPaths = 0;
+
+	return true;
+    }
+
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index 855f064..5e0db35 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -29,6 +29,13 @@
 		    String dataPathSummaryStr);
 
     /**
+     * Delete all previously added flows.
+     *
+     * @return true on success, otherwise false.
+     */
+    boolean deleteAllFlows();
+
+    /**
      * Delete a previously added flow.
      *
      * @param flowId the Flow ID of the flow to delete.
@@ -37,6 +44,13 @@
     boolean deleteFlow(FlowId flowId);
 
     /**
+     * Clear the state for all previously added flows.
+     *
+     * @return true on success, otherwise false.
+     */
+    boolean clearAllFlows();
+
+    /**
      * Clear the state for a previously added flow.
      *
      * @param flowId the Flow ID of the flow to clear.
@@ -101,4 +115,39 @@
      * @return the added shortest-path flow on success, otherwise null.
      */
     public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath);
+
+    /**
+     * Store a path flow for measurement purpose.
+     *
+     * NOTE: The Flow Path argument does NOT contain flow entries.
+     *
+     * @param flowPath the Flow Path with the endpoints and the match
+     * conditions to store.
+     * @return the stored shortest-path flow on success, otherwise null.
+     */
+    public FlowPath measurementStorePathFlow(FlowPath flowPath);
+
+    /**
+     * Install path flows for measurement purpose.
+     *
+     * @param numThreads the number of threads to use to install the path
+     * flows.
+     * @return true on success, otherwise false.
+     */
+    public boolean measurementInstallPaths(Integer numThreads);
+
+    /**
+     * Get the measurement time that took to install the path flows.
+     *
+     * @return the measurement time (in nanoseconds) it took to install
+     * the path flows.
+     */
+    public Long measurementGetInstallPathsTimeNsec();
+
+    /**
+     * Clear the path flows stored for measurement purpose.
+     *
+     * @return true on success, otherwise false.
+     */
+    public boolean measurementClearAllPaths();
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/ClearFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/ClearFlowResource.java
index 8fff358..7f3b589 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/ClearFlowResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/ClearFlowResource.java
@@ -27,11 +27,16 @@
 
 	// Extract the arguments
 	String flowIdStr = (String) getRequestAttributes().get("flow-id");
-	FlowId flowId = new FlowId(flowIdStr);
-	log.debug("Clear Flow Id: " + flowIdStr);
 
 	// Process the request
-	result = flowService.clearFlow(flowId);
+	if (flowIdStr.equals("all")) {
+	    log.debug("Clear All Flows");
+	    result = flowService.clearAllFlows();
+	} else {
+	    FlowId flowId = new FlowId(flowIdStr);
+	    log.debug("Clear Flow Id: " + flowIdStr);
+	    result = flowService.clearFlow(flowId);
+	}
 	return result;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/DeleteFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/DeleteFlowResource.java
index f418c1e..ed6f0f7 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/DeleteFlowResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/DeleteFlowResource.java
@@ -27,11 +27,16 @@
 
 	// Extract the arguments
 	String flowIdStr = (String) getRequestAttributes().get("flow-id");
-	FlowId flowId = new FlowId(flowIdStr);
-	log.debug("Delete Flow Id: " + flowIdStr);
 
 	// Process the request
-	result = flowService.deleteFlow(flowId);
+	if (flowIdStr.equals("all")) {
+	    log.debug("Delete All Flows");
+	    result = flowService.deleteAllFlows();
+	} else {
+	    FlowId flowId = new FlowId(flowIdStr);
+	    log.debug("Delete Flow Id: " + flowIdStr);
+	    result = flowService.deleteFlow(flowId);
+	}
 	return result;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
index 962dbbb..9fa5e63 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/FlowWebRoutable.java
@@ -22,6 +22,10 @@
         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);
+        router.attach("/measurement-store-path/json", MeasurementStorePathFlowResource.class);
+        router.attach("/measurement-install-paths/{num-threads}/json", MeasurementInstallPathsFlowResource.class);
+        router.attach("/measurement-get-install-paths-time-nsec/json", MeasurementGetInstallPathsTimeNsecFlowResource.class);
+        router.attach("/measurement-clear-all-paths/json", MeasurementClearAllPathsFlowResource.class);
         return router;
     }
 
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementClearAllPathsFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementClearAllPathsFlowResource.java
new file mode 100644
index 0000000..f69180d
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementClearAllPathsFlowResource.java
@@ -0,0 +1,35 @@
+package net.floodlightcontroller.flowcache.web;
+
+import net.floodlightcontroller.flowcache.IFlowService;
+import net.floodlightcontroller.util.FlowId;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MeasurementClearAllPathsFlowResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(MeasurementClearAllPathsFlowResource.class);
+
+    @Get("json")
+    public Boolean retrieve() {
+	Boolean result = false;
+
+        IFlowService flowService =
+                (IFlowService)getContext().getAttributes().
+                get(IFlowService.class.getCanonicalName());
+
+        if (flowService == null) {
+	    log.debug("ONOS Flow Service not found");
+            return result;
+	}
+
+	// Extract the arguments
+	log.debug("Measurement Clear All Paths");
+
+	// Process the request
+	result = flowService.measurementClearAllPaths();
+	return result;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementGetInstallPathsTimeNsecFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
new file mode 100644
index 0000000..3dc1d08
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementGetInstallPathsTimeNsecFlowResource.java
@@ -0,0 +1,37 @@
+package net.floodlightcontroller.flowcache.web;
+
+import net.floodlightcontroller.flowcache.IFlowService;
+import net.floodlightcontroller.util.FlowId;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MeasurementGetInstallPathsTimeNsecFlowResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(MeasurementGetInstallPathsTimeNsecFlowResource.class);
+
+    @Get("json")
+    public Long retrieve() {
+	Long result = null;
+
+        IFlowService flowService =
+                (IFlowService)getContext().getAttributes().
+                get(IFlowService.class.getCanonicalName());
+
+        if (flowService == null) {
+	    log.debug("ONOS Flow Service not found");
+	    return result;
+	}
+
+	// Extract the arguments
+
+	// Process the request
+	result = flowService.measurementGetInstallPathsTimeNsec();
+
+	log.debug("Measurement Get Install Paths Time (nsec): " + result);
+
+	return result;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementInstallPathsFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementInstallPathsFlowResource.java
new file mode 100644
index 0000000..1bba4b1
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementInstallPathsFlowResource.java
@@ -0,0 +1,37 @@
+package net.floodlightcontroller.flowcache.web;
+
+import net.floodlightcontroller.flowcache.IFlowService;
+import net.floodlightcontroller.util.FlowId;
+
+import org.openflow.util.HexString;
+import org.restlet.resource.Get;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MeasurementInstallPathsFlowResource extends ServerResource {
+    protected static Logger log = LoggerFactory.getLogger(MeasurementInstallPathsFlowResource.class);
+
+    @Get("json")
+    public Boolean retrieve() {
+	Boolean result = false;
+
+        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 numThreadsStr = (String) getRequestAttributes().get("num-threads");
+	Integer numThreads = new Integer(numThreadsStr);
+	log.debug("Measurement Install Paths Number of Threads " + numThreadsStr);
+
+	// Process the request
+	result = flowService.measurementInstallPaths(numThreads);
+	return result;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementStorePathFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementStorePathFlowResource.java
new file mode 100644
index 0000000..e68ceb7
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/MeasurementStorePathFlowResource.java
@@ -0,0 +1,65 @@
+package net.floodlightcontroller.flowcache.web;
+
+import java.io.IOException;
+
+import net.floodlightcontroller.flowcache.IFlowService;
+import net.floodlightcontroller.util.FlowId;
+import net.floodlightcontroller.util.FlowPath;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.restlet.resource.Post;
+import org.restlet.resource.ServerResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MeasurementStorePathFlowResource extends ServerResource {
+
+    protected static Logger log = LoggerFactory.getLogger(MeasurementStorePathFlowResource.class);
+
+    @Post("json")
+    public FlowId store(String flowJson) {
+	FlowId result = new FlowId();
+
+        IFlowService flowService =
+                (IFlowService)getContext().getAttributes().
+                get(IFlowService.class.getCanonicalName());
+
+        if (flowService == null) {
+	    log.debug("ONOS Flow Service not found");
+            return result;
+	}
+
+	//
+	// Extract the arguments
+	// NOTE: The "flow" is specified in JSON format.
+	//
+	ObjectMapper mapper = new ObjectMapper();
+	String flowPathStr = flowJson;
+	FlowPath flowPath = null;
+	log.debug("Measurement Store Flow Path: " + flowPathStr);
+	try {
+	    flowPath = mapper.readValue(flowPathStr, FlowPath.class);
+	} catch (JsonGenerationException e) {
+	    e.printStackTrace();
+	} catch (JsonMappingException e) {
+	    e.printStackTrace();
+	} catch (IOException e) {
+	    e.printStackTrace();
+	}
+
+	// Process the request
+	if (flowPath != null) {
+	    FlowPath addedFlowPath =
+		flowService.measurementStorePathFlow(flowPath);
+	    if (addedFlowPath == null)
+		result = new FlowId();		// Error: Return empty Flow Id
+	    else
+		result = addedFlowPath.flowId();
+	}
+
+        return result;
+    }
+}
diff --git a/web/clear_flow.py b/web/clear_flow.py
index 50678e2..db70d40 100755
--- a/web/clear_flow.py
+++ b/web/clear_flow.py
@@ -51,6 +51,7 @@
   usage_msg = usage_msg + "    Arguments:\n"
   usage_msg = usage_msg + "        <begin-flow-id> <end-flow-id>      Clear all flows in the flow ID range\n"
   usage_msg = usage_msg + "        <flow-id>                          Clear a single flow with the flow ID\n"
+  usage_msg = usage_msg + "        all                                Clear all flows\n"
 
   # app.debug = False;
 
@@ -63,14 +64,18 @@
   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 = begin_flow_id
-  while flow_id <= end_flow_id:
-    clear_flow_path(flow_id)
-    flow_id = flow_id + 1
+  if (sys.argv[1] == "all"):
+    clear_flow_path(sys.argv[1])
+  else:
+    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 = 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 ff4caff..fff9319 100755
--- a/web/delete_flow.py
+++ b/web/delete_flow.py
@@ -51,6 +51,7 @@
   usage_msg = usage_msg + "    Arguments:\n"
   usage_msg = usage_msg + "        <begin-flow-id> <end-flow-id>      Delete all flows in the flow ID range\n"
   usage_msg = usage_msg + "        <flow-id>                          Delete a single flow with the flow ID\n"
+  usage_msg = usage_msg + "        all                                Delete all flows\n"
 
   # app.debug = False;
 
@@ -63,14 +64,18 @@
   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 = begin_flow_id
-  while flow_id <= end_flow_id:
-    delete_flow_path(flow_id)
-    flow_id = flow_id + 1
+  if (sys.argv[1] == "all"):
+    delete_flow_path(sys.argv[1])
+  else:
+    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 = begin_flow_id
+    while flow_id <= end_flow_id:
+      delete_flow_path(flow_id)
+      flow_id = flow_id + 1
diff --git a/web/measurement_clear_all_paths.py b/web/measurement_clear_all_paths.py
new file mode 100755
index 0000000..5bb73c5
--- /dev/null
+++ b/web/measurement_clear_all_paths.py
@@ -0,0 +1,61 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+#
+# TODO: remove this! We don't use JSON argument here!
+# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
+#
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+# @app.route("/wm/flow/measurement-clear-all-paths/json")
+def measurement_clear_all_paths():
+  command = "curl -s \"http://%s:%s/wm/flow/measurement-clear-all-paths/json\"" % (ControllerIP, ControllerPort)
+  debug("measurement_clear_all_paths %s" % command)
+  result = os.popen(command).read()
+  debug("result %s" % result)
+  # parsedResult = json.loads(result)
+  # debug("parsed %s" % parsedResult)
+
+if __name__ == "__main__":
+  usage_msg = "Clear the paths that have been stored for measurement purpose\n"
+  usage_msg = usage_msg + "Usage: %s\n" % (sys.argv[0])
+  usage_msg = usage_msg + "\n"
+
+  # 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
+
+  # Do the work
+  measurement_clear_all_paths()
diff --git a/web/measurement_get_install_paths_time_nsec.py b/web/measurement_get_install_paths_time_nsec.py
new file mode 100755
index 0000000..d64dc49
--- /dev/null
+++ b/web/measurement_get_install_paths_time_nsec.py
@@ -0,0 +1,61 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+#
+# TODO: remove this! We don't use JSON argument here!
+# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
+#
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+# @app.route("/wm/flow/measurement-get-install-paths-time-nsec/json")
+def measurement_get_install_paths_time_nsec():
+  command = "curl -s \"http://%s:%s/wm/flow/measurement-get-install-paths-time-nsec/json\"" % (ControllerIP, ControllerPort)
+  debug("measurement_get_install_paths_time_nsec %s" % command)
+  result = os.popen(command).read()
+  print '%s nsec' % (result)
+  # parsedResult = json.loads(result)
+  # debug("parsed %s" % parsedResult)
+
+if __name__ == "__main__":
+  usage_msg = "Get the measured time to install the stored flow paths\n"
+  usage_msg = usage_msg + "Usage: %s\n" % (sys.argv[0])
+  usage_msg = usage_msg + "\n"
+
+  # 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
+
+  # Do the work
+  measurement_get_install_paths_time_nsec()
diff --git a/web/measurement_install_paths.py b/web/measurement_install_paths.py
new file mode 100755
index 0000000..d99070e
--- /dev/null
+++ b/web/measurement_install_paths.py
@@ -0,0 +1,67 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+#
+# TODO: remove this! We don't use JSON argument here!
+# curl http://127.0.0.1:8080/wm/flow/delete/{"value":"0xf"}/json'
+#
+
+## Global Var ##
+ControllerIP="127.0.0.1"
+ControllerPort=8080
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+# @app.route("/wm/flow/measurement-install-paths/<num-threads>/json")
+def measurement_install_paths(num_threads):
+  command = "curl -s \"http://%s:%s/wm/flow/measurement-install-paths/%s/json\"" % (ControllerIP, ControllerPort, num_threads)
+  debug("measurement_install_paths %s" % command)
+  result = os.popen(command).read()
+  debug("result %s" % result)
+  # parsedResult = json.loads(result)
+  # debug("parsed %s" % parsedResult)
+
+if __name__ == "__main__":
+  usage_msg = "Install flow paths and start measurements\n"
+  usage_msg = usage_msg + "Usage: %s <num-threads>\n" % (sys.argv[0])
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Arguments:\n"
+  usage_msg = usage_msg + "        <num-threads>      Number of threads to use to install the flows\n"
+
+  # 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) < 2:
+    log_error(usage_msg)
+    exit(1)
+  num_threads = int(sys.argv[1], 0)
+
+  # Do the work
+  measurement_install_paths(num_threads)
diff --git a/web/measurement_store_flow.py b/web/measurement_store_flow.py
new file mode 100755
index 0000000..637ab3e
--- /dev/null
+++ b/web/measurement_store_flow.py
@@ -0,0 +1,447 @@
+#! /usr/bin/env python
+# -*- Mode: python; py-indent-offset: 4; tab-width: 8; indent-tabs-mode: t; -*-
+
+import copy
+import pprint
+import os
+import sys
+import subprocess
+import json
+import argparse
+import io
+import time
+
+from flask import Flask, json, Response, render_template, make_response, request
+
+## Global Var ##
+ControllerIP = "127.0.0.1"
+ControllerPort = 8080
+ReadFromFile = ""
+
+DEBUG=0
+pp = pprint.PrettyPrinter(indent=4)
+
+app = Flask(__name__)
+
+## Worker Functions ##
+def log_error(txt):
+  print '%s' % (txt)
+
+def debug(txt):
+  if DEBUG:
+    print '%s' % (txt)
+
+def measurement_store_path_flow(flow_path):
+  flow_path_json = json.dumps(flow_path)
+
+  try:
+    command = "curl -s -H 'Content-Type: application/json' -d '%s' http://%s:%s/wm/flow/measurement-store-path/json" % (flow_path_json, ControllerIP, ControllerPort)
+    debug("measurement_store_path_flow %s" % command)
+    result = os.popen(command).read()
+    debug("result %s" % result)
+    # parsedResult = json.loads(result)
+    # debug("parsed %s" % parsedResult)
+  except:
+    log_error("Controller IF has issue")
+    exit(1)
+
+def extract_flow_args(my_args):
+  # Check the arguments
+  if len(my_args) < 6:
+    log_error(usage_msg)
+    exit(1)
+
+  # Extract the mandatory arguments
+  my_flow_id = my_args[0]
+  my_installer_id = my_args[1]
+  my_src_dpid = my_args[2]
+  my_src_port = my_args[3]
+  my_dst_dpid = my_args[4]
+  my_dst_port = my_args[5]
+
+  #
+  # Extract the "match" and "action" arguments
+  #
+  match = {}
+  matchInPortEnabled = True		# NOTE: Enabled by default
+  actions = []
+  actionOutputEnabled = True		# NOTE: Enabled by default
+  idx = 6
+  while idx < len(my_args):
+    action = {}
+    arg1 = my_args[idx]
+    idx = idx + 1
+    # Extract the second argument
+    if idx >= len(my_args):
+      error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
+      log_error(error_arg)
+      log_error(usage_msg)
+      exit(1)
+    arg2 = my_args[idx]
+    idx = idx + 1
+
+    if arg1 == "matchInPort":
+      # Just mark whether inPort matching is enabled
+      matchInPortEnabled = arg2 in ['True', 'true']
+      # inPort = {}
+      # inPort['value'] = int(arg2, 0)
+      # match['inPort'] = inPort
+      ## match['matchInPort'] = True
+    elif arg1 == "matchSrcMac":
+      srcMac = {}
+      srcMac['value'] = arg2
+      match['srcMac'] = srcMac
+      # match['matchSrcMac'] = True
+    elif arg1 == "matchDstMac":
+      dstMac = {}
+      dstMac['value'] = arg2
+      match['dstMac'] = dstMac
+      # match['matchDstMac'] = True
+    elif arg1 == "matchVlanId":
+      match['vlanId'] = int(arg2, 0)
+      # match['matchVlanId'] = True
+    elif arg1 == "matchVlanPriority":
+      match['vlanPriority'] = int(arg2, 0)
+      # match['matchVlanPriority'] = True
+    elif arg1 == "matchEthernetFrameType":
+      match['ethernetFrameType'] = int(arg2, 0)
+      # match['matchEthernetFrameType'] = True
+    elif arg1 == "matchIpToS":
+      match['ipToS'] = int(arg2, 0)
+      # match['matchIpToS'] = True
+    elif arg1 == "matchIpProto":
+      match['ipProto'] = int(arg2, 0)
+      # match['matchIpProto'] = True
+    elif arg1 == "matchSrcIPv4Net":
+      srcIPv4Net = {}
+      srcIPv4Net['value'] = arg2
+      match['srcIPv4Net'] = srcIPv4Net
+      # match['matchSrcIPv4Net'] = True
+    elif arg1 == "matchDstIPv4Net":
+      dstIPv4Net = {}
+      dstIPv4Net['value'] = arg2
+      match['dstIPv4Net'] = dstIPv4Net
+      # match['matchDstIPv4Net'] = True
+    elif arg1 == "matchSrcTcpUdpPort":
+      match['srcTcpUdpPort'] = int(arg2, 0)
+      # match['matchSrcTcpUdpPort'] = True
+    elif arg1 == "matchDstTcpUdpPort":
+      match['dstTcpUdpPort'] = int(arg2, 0)
+      # match['matchDstTcpUdpPort'] = True
+    elif arg1 == "actionOutput":
+      # Just mark whether ACTION_OUTPUT action is enabled
+      actionOutputEnabled = arg2 in ['True', 'true']
+      #
+      # TODO: Complete the implementation for ACTION_OUTPUT
+      #   actionOutput = {}
+      #   outPort = {}
+      #   outPort['value'] = int(arg2, 0)
+      #   actionOutput['port'] = outPort
+      #   actionOutput['maxLen'] = int(arg3, 0)
+      #   action['actionOutput'] = actionOutput
+      #   # action['actionType'] = 'ACTION_OUTPUT'
+      #   actions.append(action)
+      #
+    elif arg1 == "actionSetVlanId":
+      vlanId = {}
+      vlanId['vlanId'] = int(arg2, 0)
+      action['actionSetVlanId'] = vlanId
+      # action['actionType'] = 'ACTION_SET_VLAN_VID'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetVlanPriority":
+      vlanPriority = {}
+      vlanPriority['vlanPriority'] = int(arg2, 0)
+      action['actionSetVlanPriority'] = vlanPriority
+      # action['actionType'] = 'ACTION_SET_VLAN_PCP'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetIpToS":
+      ipToS = {}
+      ipToS['ipToS'] = int(arg2, 0)
+      action['actionSetIpToS'] = ipToS
+      # action['actionType'] = 'ACTION_SET_NW_TOS'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetTcpUdpSrcPort":
+      tcpUdpSrcPort = {}
+      tcpUdpSrcPort['port'] = int(arg2, 0)
+      action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
+      # action['actionType'] = 'ACTION_SET_TP_SRC'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetTcpUdpDstPort":
+      tcpUdpDstPort = {}
+      tcpUdpDstPort['port'] = int(arg2, 0)
+      action['actionSetTcpUdpDstPort'] = tcpUdpDstPort
+      # action['actionType'] = 'ACTION_SET_TP_DST'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionStripVlan":
+      stripVlan = {}
+      stripVlan['stripVlan'] = arg2 in ['True', 'true']
+      action['actionStripVlan'] = stripVlan
+      # action['actionType'] = 'ACTION_STRIP_VLAN'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetEthernetSrcAddr":
+      ethernetSrcAddr = {}
+      ethernetSrcAddr['value'] = arg2
+      setEthernetSrcAddr = {}
+      setEthernetSrcAddr['addr'] = ethernetSrcAddr
+      action['actionSetEthernetSrcAddr'] = setEthernetSrcAddr
+      # action['actionType'] = 'ACTION_SET_DL_SRC'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetEthernetDstAddr":
+      ethernetDstAddr = {}
+      ethernetDstAddr['value'] = arg2
+      setEthernetDstAddr = {}
+      setEthernetDstAddr['addr'] = ethernetDstAddr
+      action['actionSetEthernetDstAddr'] = setEthernetDstAddr
+      # action['actionType'] = 'ACTION_SET_DL_DST'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetIPv4SrcAddr":
+      IPv4SrcAddr = {}
+      IPv4SrcAddr['value'] = arg2
+      setIPv4SrcAddr = {}
+      setIPv4SrcAddr['addr'] = IPv4SrcAddr
+      action['actionSetIPv4SrcAddr'] = setIPv4SrcAddr
+      # action['actionType'] = 'ACTION_SET_NW_SRC'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetIPv4DstAddr":
+      IPv4DstAddr = {}
+      IPv4DstAddr['value'] = arg2
+      setIPv4DstAddr = {}
+      setIPv4DstAddr['addr'] = IPv4DstAddr
+      action['actionSetIPv4DstAddr'] = setIPv4DstAddr
+      # action['actionType'] = 'ACTION_SET_NW_DST'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionEnqueue":
+      # TODO: Implement ACTION_ENQUEUE
+      actionEnqueue = {}
+      #   actionEnqueue['queueId'] = int(arg2, 0)
+      #   enqueuePort = {}
+      #   enqueuePort['value'] = int(arg3, 0)
+      #   actionEnqueue['port'] = enqueuePort
+      #   action['actionEnqueue'] = actionEnqueue
+      #   # action['actionType'] = 'ACTION_ENQUEUE'
+      #   actions.append(copy.deepcopy(action))
+      #
+    else:
+      log_error("ERROR: Unknown argument '%s'" % (arg1))
+      log_error(usage_msg)
+      exit(1)
+
+  return {
+    'my_flow_id' : my_flow_id,
+    'my_installer_id' : my_installer_id,
+    'my_src_dpid' : my_src_dpid,
+    'my_src_port' : my_src_port,
+    'my_dst_dpid' : my_dst_dpid,
+    'my_dst_port' : my_dst_port,
+    'match' : match,
+    'matchInPortEnabled' : matchInPortEnabled,
+    'actions' : actions,
+    'actionOutputEnabled' : actionOutputEnabled
+    }
+
+def compute_flow_path(parsed_args, data_path):
+
+  my_flow_id = parsed_args['my_flow_id']
+  my_installer_id = parsed_args['my_installer_id']
+  match = parsed_args['match']
+  matchInPortEnabled = parsed_args['matchInPortEnabled']
+  actions = parsed_args['actions']
+  actionOutputEnabled = parsed_args['actionOutputEnabled']
+  my_data_path = copy.deepcopy(data_path)
+
+  flow_id = {}
+  flow_id['value'] = my_flow_id
+  installer_id = {}
+  installer_id['value'] = my_installer_id
+
+  flow_path = {}
+  flow_path['flowId'] = flow_id
+  flow_path['installerId'] = installer_id
+
+  if (len(match) > 0):
+    flow_path['flowEntryMatch'] = copy.deepcopy(match)
+
+  #
+  # Add the match conditions to each flow entry
+  #
+  if (len(match) > 0) or matchInPortEnabled:
+    idx = 0
+    while idx < len(my_data_path['flowEntries']):
+      if matchInPortEnabled:
+	inPort = my_data_path['flowEntries'][idx]['inPort']
+	match['inPort'] = copy.deepcopy(inPort)
+	# match['matchInPort'] = True
+      my_data_path['flowEntries'][idx]['flowEntryMatch'] = copy.deepcopy(match)
+      idx = idx + 1
+
+  #
+  # Set the actions for each flow entry
+  # NOTE: The actions from the command line are aplied
+  # ONLY to the first flow entry.
+  #
+  # If ACTION_OUTPUT action is enabled, then apply it
+  # to each flow entry.
+  #
+  if (len(actions) > 0) or actionOutputEnabled:
+    idx = 0
+    while idx < len(my_data_path['flowEntries']):
+      if idx > 0:
+	actions = []	# Reset the actions for all but first entry
+      action = {}
+      outPort = my_data_path['flowEntries'][idx]['outPort']
+      actionOutput = {}
+      actionOutput['port'] = copy.deepcopy(outPort)
+      # actionOutput['maxLen'] = 0	# TODO: not used for now
+      action['actionOutput'] = copy.deepcopy(actionOutput)
+      # action['actionType'] = 'ACTION_OUTPUT'
+      actions.append(copy.deepcopy(action))
+
+      my_data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
+      idx = idx + 1
+
+
+  flow_path['dataPath'] = my_data_path
+  debug("Flow Path: %s" % flow_path)
+  return flow_path
+
+def measurement_store_paths(parsed_args):
+  idx = 0
+  while idx < len(parsed_args):
+    data_path = {}
+    src_dpid = {}
+    src_port = {}
+    dst_dpid = {}
+    dst_port = {}
+    src_switch_port = {}
+    dst_switch_port = {}
+    flow_entries = []
+
+    src_dpid['value'] = parsed_args[idx]['my_src_dpid']
+    src_port['value'] = parsed_args[idx]['my_src_port']
+    dst_dpid['value'] = parsed_args[idx]['my_dst_dpid']
+    dst_port['value'] = parsed_args[idx]['my_dst_port']
+    src_switch_port['dpid'] = src_dpid
+    src_switch_port['port'] = src_port
+    dst_switch_port['dpid'] = dst_dpid
+    dst_switch_port['port'] = dst_port
+
+    data_path['srcPort'] = copy.deepcopy(src_switch_port)
+    data_path['dstPort'] = copy.deepcopy(dst_switch_port)
+    data_path['flowEntries'] = copy.deepcopy(flow_entries)
+
+    #
+    # XXX: Explicitly disable the InPort matching, and
+    # the Output action, because they get in the way
+    # during the compute_flow_path() processing.
+    #
+    parsed_args[idx]['matchInPortEnabled'] = False
+    parsed_args[idx]['actionOutputEnabled'] = False
+
+    flow_path = compute_flow_path(parsed_args[idx], data_path)
+    measurement_store_path_flow(flow_path)
+
+    idx = idx + 1
+
+
+if __name__ == "__main__":
+  usage_msg = "Store Flow Paths into ONOS for measurement purpose.\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "Usage: %s [Flags] <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Flags:\n"
+  usage_msg = usage_msg + "        -f <filename>     Read the flow(s) to install from a file\n"
+  usage_msg = usage_msg + "                          File format: one line per flow starting with <flow-id>\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Match Conditions:\n"
+  usage_msg = usage_msg + "        matchInPort <True|False> (default to True)\n"
+  usage_msg = usage_msg + "        matchSrcMac <source MAC address>\n"
+  usage_msg = usage_msg + "        matchDstMac <destination MAC address>\n"
+  usage_msg = usage_msg + "        matchSrcIPv4Net <source IPv4 network address>\n"
+  usage_msg = usage_msg + "        matchDstIPv4Net <destination IPv4 network address>\n"
+  usage_msg = usage_msg + "        matchEthernetFrameType <Ethernet frame type>\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Match Conditions (not implemented yet):\n"
+  usage_msg = usage_msg + "        matchVlanId <VLAN ID>\n"
+  usage_msg = usage_msg + "        matchVlanPriority <VLAN priority>\n"
+  usage_msg = usage_msg + "        matchIpToS <IP ToS (DSCP field, 6 bits)>\n"
+  usage_msg = usage_msg + "        matchIpProto <IP protocol>\n"
+  usage_msg = usage_msg + "        matchSrcTcpUdpPort <source TCP/UDP port>\n"
+  usage_msg = usage_msg + "        matchDstTcpUdpPort <destination TCP/UDP port>\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Actions:\n"
+  usage_msg = usage_msg + "        actionOutput <True|False> (default to True)\n"
+  usage_msg = usage_msg + "        actionSetEthernetSrcAddr <source MAC address>\n"
+  usage_msg = usage_msg + "        actionSetEthernetDstAddr <destination MAC address>\n"
+  usage_msg = usage_msg + "        actionSetIPv4SrcAddr <source IPv4 address>\n"
+  usage_msg = usage_msg + "        actionSetIPv4DstAddr <destination IPv4 address>\n"
+  usage_msg = usage_msg + "\n"
+  usage_msg = usage_msg + "    Actions (not implemented yet):\n"
+  usage_msg = usage_msg + "        actionSetVlanId <VLAN ID>\n"
+  usage_msg = usage_msg + "        actionSetVlanPriority <VLAN priority>\n"
+  usage_msg = usage_msg + "        actionSetIpToS <IP ToS (DSCP field, 6 bits)>\n"
+  usage_msg = usage_msg + "        actionSetTcpUdpSrcPort <source TCP/UDP port>\n"
+  usage_msg = usage_msg + "        actionSetTcpUdpDstPort <destination TCP/UDP port>\n"
+  usage_msg = usage_msg + "        actionStripVlan <True|False>\n"
+  usage_msg = usage_msg + "        actionEnqueue <dummy argument>\n"
+
+  # 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 the flags
+  #
+  start_argv_index = 1
+  idx = 1
+  while idx < len(sys.argv):
+    arg1 = sys.argv[idx]
+    idx = idx + 1
+    if arg1 == "-f":
+      if idx >= len(sys.argv):
+	error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
+	log_error(error_arg)
+	log_error(usage_msg)
+	exit(1)
+      ReadFromFile = sys.argv[idx]
+      idx = idx + 1
+      start_argv_index = idx
+    else:
+      break;
+
+  #
+  # Read the arguments from a file or from the remaining command line options
+  #
+  my_lines = []
+  if len(ReadFromFile) > 0:
+    f = open(ReadFromFile, "rt")
+    my_line = f.readline()
+    while my_line:
+      if len(my_line.rstrip()) > 0 and my_line[0] != "#":
+	my_token_line = my_line.rstrip().split()
+	my_lines.append(my_token_line)
+      my_line = f.readline()
+  else:
+    my_lines.append(copy.deepcopy(sys.argv[start_argv_index:]))
+
+  #
+  # Initialization
+  #
+  last_data_paths = []
+  parsed_args = []
+  idx = 0
+  while idx < len(my_lines):
+    last_data_path = []
+    last_data_paths.append(copy.deepcopy(last_data_path))
+    #
+    # Parse the flow arguments
+    #
+    my_args = my_lines[idx]
+    parsed_args.append(copy.deepcopy(extract_flow_args(my_args)))
+
+    idx = idx + 1
+
+  #
+  measurement_store_paths(parsed_args)
diff --git a/web/shortest_path.py b/web/shortest_path.py
index b379a82..0f23bf4 100755
--- a/web/shortest_path.py
+++ b/web/shortest_path.py
@@ -20,7 +20,7 @@
 ControllerIP="127.0.0.1"
 ControllerPort=8080
 
-DEBUG=1
+DEBUG=0
 pp = pprint.PrettyPrinter(indent=4)
 
 app = Flask(__name__)