Merge branch 'master' of https://github.com/OPENNETWORKINGLAB/ONOS
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index 9dea4c5..ea0daa3 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -193,6 +193,12 @@
 		@Property("dst_port")
 		public void setDstPort(Short dstPort);
 
+		@Property("data_path_summary")
+		public String getDataPathSummary();
+
+		@Property("data_path_summary")
+		public void setDataPathSummary(String dataPathSummary);
+
 		@Adjacency(label="flow", direction=Direction.IN)
 		public Iterable<IFlowEntry> getFlowEntries();
 
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index 25cf367..34e6296 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -263,7 +263,6 @@
 		    log.debug("FloodlightProvider service not found!");
 		    return;
 		}
-
 		Map<Long, IOFSwitch> mySwitches =
 		    floodlightProvider.getSwitches();
 		Map<Long, IFlowEntry> myFlowEntries =
@@ -272,6 +271,77 @@
 		    new LinkedList<IFlowEntry>();
 
 		//
+		// 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) {
+		    if (flowPathObj == null)
+			continue;
+		    String dataPathSummaryStr = flowPathObj.getDataPathSummary();
+		    if (dataPathSummaryStr == null)
+			continue;	// Could be invalid entry?
+		    if (dataPathSummaryStr.isEmpty())
+			continue;	// No need to maintain this flow
+
+		    // Fetch the fields needed to recompute the shortest path
+		    String flowIdStr = flowPathObj.getFlowId();
+		    String srcDpidStr = flowPathObj.getSrcSwitch();
+		    Short srcPortShort = flowPathObj.getSrcPort();
+		    String dstDpidStr = flowPathObj.getDstSwitch();
+		    Short dstPortShort = flowPathObj.getDstPort();
+		    if ((flowIdStr == null) ||
+			(srcDpidStr == null) ||
+			(srcPortShort == null) ||
+			(dstDpidStr == null) ||
+			(dstPortShort == null)) {
+			log.debug("IGNORING Flow Path entry with null fields");
+			continue;
+		    }
+
+		    FlowId flowId = new FlowId(flowIdStr);
+		    Dpid srcDpid = new Dpid(srcDpidStr);
+		    Port srcPort = new Port(srcPortShort);
+		    Dpid dstDpid = new Dpid(dstDpidStr);
+		    Port dstPort = new Port(dstPortShort);
+		    SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
+		    SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
+		    DataPath dataPath =
+			topoRouteService.getTopoShortestPath(srcSwitchPort,
+							     dstSwitchPort);
+		    String newDataPathSummaryStr = dataPath.dataPathSummary();
+		    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);
+		}
+		reconcileFlows(flowObjSet);
+		topoRouteService.dropShortestPathTopo();
+		*/
+
+		//
 		// Fetch all Flow Entries and select only my Flow Entries
 		// that need to be undated into the switches.
 		//
@@ -593,10 +663,13 @@
      *
      * @param flowPath the Flow Path to install.
      * @param flowId the return-by-reference Flow ID as assigned internally.
+     * @param dataPathSummaryStr the data path summary string if the added
+     * flow will be maintained internally, otherwise null.
      * @return true on success, otherwise false.
      */
     @Override
-    public boolean addFlow(FlowPath flowPath, FlowId flowId) {
+    public boolean addFlow(FlowPath flowPath, FlowId flowId,
+			   String dataPathSummaryStr) {
 	if (flowPath.flowId().value() == measurementFlowId) {
 	    modifiedMeasurementFlowTime = System.nanoTime();
 	}
@@ -654,6 +727,12 @@
 	flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
 	flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
 
+	if (dataPathSummaryStr != null) {
+	    flowObj.setDataPathSummary(dataPathSummaryStr);
+	} else {
+	    flowObj.setDataPathSummary("");
+	}
+
 	// Flow edges:
 	//   HeadFE
 
@@ -1041,14 +1120,14 @@
 		    return flowPaths;
 		}
 	
-		Collections.sort(allFlows);
+//		Collections.sort(allFlows);
 		
 		for (FlowPath flow : allFlows) {
 			
 			// start from desired flowId
-			if (flow.flowId().value() < flowId.value()) {
-				continue;
-			}
+			//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()) {
@@ -1125,16 +1204,16 @@
 	String flowIdStr = flowObj.getFlowId();
 	String installerIdStr = flowObj.getInstallerId();
 	String srcSwitchStr = flowObj.getSrcSwitch();
-	Short srcPortStr = flowObj.getSrcPort();
+	Short srcPortShort = flowObj.getSrcPort();
 	String dstSwitchStr = flowObj.getDstSwitch();
-	Short dstPortStr = flowObj.getDstPort();
+	Short dstPortShort = flowObj.getDstPort();
 
 	if ((flowIdStr == null) ||
 	    (installerIdStr == null) ||
 	    (srcSwitchStr == null) ||
-	    (srcPortStr == null) ||
+	    (srcPortShort == null) ||
 	    (dstSwitchStr == null) ||
-	    (dstPortStr == null)) {
+	    (dstPortShort == null)) {
 	    // TODO: A work-around, becauuse of some bogus database objects
 	    return null;
 	}
@@ -1142,9 +1221,9 @@
 	flowPath.setFlowId(new FlowId(flowIdStr));
 	flowPath.setInstallerId(new CallerId(installerIdStr));
 	flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
-	flowPath.dataPath().srcPort().setPort(new Port(srcPortStr));
+	flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
 	flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
-	flowPath.dataPath().dstPort().setPort(new Port(dstPortStr));
+	flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
 
 	//
 	// Extract all Flow Entries
@@ -1229,6 +1308,8 @@
      */
     @Override
     public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
+	String dataPathSummaryStr = null;
+
 	//
 	// Do the shortest path computation
 	//
@@ -1243,6 +1324,9 @@
 	    userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
 	}
 
+	// Compute the Data Path summary
+	dataPathSummaryStr = dataPath.dataPathSummary();
+
 	//
 	// Set the incoming port matching and the outgoing port output
 	// actions for each flow entry.
@@ -1277,7 +1361,7 @@
 	computedFlowPath.setDataPath(dataPath);
 
 	FlowId flowId = new FlowId();
-	if (! addFlow(computedFlowPath, flowId))
+	if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
 	    return null;
 
 	// TODO: Mark the flow for maintenance purpose
@@ -1352,21 +1436,37 @@
 	    if (flowObj != null)
 		flowObjSet.add(flowObj);
 	}
-	// conn.endTx(Transaction.COMMIT);
+
+	// Reconcile the affected flows
+	reconcileFlows(flowObjSet);
+    }
+
+    /**
+     * Reconcile all flows in a set.
+     *
+     * @param flowObjSet the set of flows that need to be reconciliated.
+     */
+    public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
+	if (! flowObjSet.iterator().hasNext())
+	    return;
 
 	//
 	// Remove the old Flow Entries, and add the new Flow Entries
 	//
+
 	Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
+	LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
 	for (IFlowPath flowObj : flowObjSet) {
 	    FlowPath flowPath = extractFlowPath(flowObj);
 	    if (flowPath == null)
 		continue;
+	    flowPaths.add(flowPath);
 
 	    //
 	    // Remove my Flow Entries from the Network MAP
 	    //
 	    Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
+	    LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
 	    for (IFlowEntry flowEntryObj : flowEntries) {
 		String dpidStr = flowEntryObj.getSwitchDpid();
 		if (dpidStr == null)
@@ -1375,10 +1475,15 @@
 		IOFSwitch mySwitch = mySwitches.get(dpid.value());
 		if (mySwitch == null)
 		    continue;		// Ignore the entry: not my switch
+		deleteFlowEntries.add(flowEntryObj);
+	    }
+	    for (IFlowEntry flowEntryObj : deleteFlowEntries) {
 		flowObj.removeFlowEntry(flowEntryObj);
 		conn.utils().removeFlowEntry(conn, flowEntryObj);
 	    }
+	}
 
+	for (FlowPath flowPath : flowPaths) {
 	    //
 	    // Delete the flow entries from the switches
 	    //
diff --git a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
index b6df1e2..619d36b 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/IFlowService.java
@@ -20,9 +20,12 @@
      *
      * @param flowPath the Flow Path to install.
      * @param flowId the return-by-reference Flow ID as assigned internally.
+     * @param dataPathSummaryStr the data path summary string if the added
+     * flow will be maintained internally, otherwise null.
      * @return true on success, otherwise false.
      */
-    boolean addFlow(FlowPath flowPath, FlowId flowId);
+    boolean addFlow(FlowPath flowPath, FlowId flowId,
+		    String dataPathSummaryStr);
 
     /**
      * Delete a previously added flow.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java b/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java
index cdccae1..e266e2e 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/web/AddFlowResource.java
@@ -52,7 +52,7 @@
 
 	// Process the request
 	if (flowPath != null) {
-	    if (flowService.addFlow(flowPath, result) != true) {
+	    if (flowService.addFlow(flowPath, result, null) != true) {
 		result = new FlowId();		// Error: Return empty Flow Id
 	    }
 	}
diff --git a/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
index 773083b..ca8d92f 100644
--- a/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
+++ b/src/main/java/net/floodlightcontroller/routing/TopoRouteService.java
@@ -368,7 +368,7 @@
 	Port outPort;
 	for (Node.Link link: resultPath) {
 	    // Setup the outgoing port, and add the Flow Entry
-	    outPort = new Port(link.neighborPort);
+	    outPort = new Port(link.myPort);
 
 	    FlowEntry flowEntry = new FlowEntry();
 	    flowEntry.setDpid(new Dpid(link.me.nodeId));
diff --git a/src/main/java/net/floodlightcontroller/util/DataPath.java b/src/main/java/net/floodlightcontroller/util/DataPath.java
index b2dded6..0ca0d13 100644
--- a/src/main/java/net/floodlightcontroller/util/DataPath.java
+++ b/src/main/java/net/floodlightcontroller/util/DataPath.java
@@ -79,6 +79,37 @@
     }
 
     /**
+     * Get a string with the summary of the shortest-path data path
+     * computation.
+     *
+     * NOTE: This method assumes the DataPath was created by
+     * using FlowManager::getShortestPath() so the inPort and outPort
+     * of the Flow Entries are set.
+     * NOTE: This method is a temporary solution and will be removed
+     * in the future.
+     *
+     * @return a string with the summary of the shortest-path
+     * data path computation if valid, otherwise the string "X".
+     * If the shortest-path was valid, The string has the following form:
+     * inPort/dpid/outPort;inPort/dpid/outPort;...
+     */
+    public String dataPathSummary() {
+	String resultStr = new String();
+	if (this.flowEntries != null) {
+	    for (FlowEntry flowEntry : this.flowEntries) {
+		// The data path summary string
+		resultStr = resultStr +
+		    flowEntry.inPort().toString() + "/"
+		    + flowEntry.dpid().toString() + "/" +
+		    flowEntry.outPort().toString() + ";";
+	    }
+	}
+	if (resultStr.isEmpty())
+	    resultStr = "X";		// Invalid shortest-path
+	return resultStr;
+    }
+
+    /**
      * Convert the data path to a string.
      *
      * The string has the following form:
diff --git a/web/add_flow.py b/web/add_flow.py
index 0ab6847..5a248eb 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -21,6 +21,7 @@
 ControllerIP = "127.0.0.1"
 ControllerPort = 8080
 MonitoringEnabled = False
+MonitoringByOnos = False
 ReadFromFile = ""
 
 DEBUG=0
@@ -91,6 +92,20 @@
     log_error("Controller IF has issue")
     exit(1)
 
+def add_shortest_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/add-shortest-path/json" % (flow_path_json, ControllerIP, ControllerPort)
+    debug("add_shortest_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 delete_flow_path(flow_id):
   command = "curl -s \"http://%s:%s/wm/flow/delete/%s/json\"" % (ControllerIP, ControllerPort, flow_id)
   debug("delete_flow_path %s" % command)
@@ -366,17 +381,97 @@
 
   flow_path['dataPath'] = my_data_path
   debug("Flow Path: %s" % flow_path)
+  return flow_path
 
-  add_flow_path(flow_path)
+def exec_monitoring_by_onos(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_entry = {}
+    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
+    match = parsed_args[idx]['match']
+    flow_entry['flowEntryMatch'] = match
+    flow_entries.append(flow_entry)
+
+    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)
+    add_shortest_path_flow(flow_path)
+
+    idx = idx + 1
+
+
+def exec_processing_by_script(parsed_args):
+  #
+  # Initialization
+  #
+  last_data_paths = []
+  idx = 0
+  while idx < len(parsed_args):
+    last_data_path = []
+    last_data_paths.append(copy.deepcopy(last_data_path))
+    idx = idx + 1
+
+  #
+  # Do the work: install and/or periodically monitor each flow
+  #
+  while True:
+    idx = 0
+    while idx < len(parsed_args):
+      last_data_path = last_data_paths[idx]
+      my_flow_id = parsed_args[idx]['my_flow_id']
+      data_path = compute_data_path(parsed_args[idx])
+      if data_path != last_data_path:
+	print_data_path(data_path)
+	if len(last_data_path) > 0:
+	  delete_flow_path(my_flow_id)
+	if len(data_path) > 0:
+	  flow_path = compute_flow_path(parsed_args[idx], data_path)
+	  add_flow_path(flow_path)
+	last_data_paths[idx] = copy.deepcopy(data_path)
+      idx = idx + 1
+
+    if MonitoringEnabled != True:
+      break
+    time.sleep(1)
 
 
 if __name__ == "__main__":
   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 + "        -m              Monitor and maintain the installed shortest path(s)\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 + "        -m [monitorname]  Monitor and maintain the installed shortest path(s)\n"
+  usage_msg = usage_msg + "                          If 'monitorname' is specified and is set to 'ONOS'\n"
+  usage_msg = usage_msg + "                          ((case insensitive), then the flow generation and\n"
+  usage_msg = usage_msg + "                          maintanenance is done by ONOS itself.\n"
+  usage_msg = usage_msg + "                          Otherwise, it is done by this script.\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"
@@ -427,6 +522,11 @@
     idx = idx + 1
     if arg1 == "-m":
       MonitoringEnabled = True
+      if idx < len(sys.argv):
+	arg2 = sys.argv[idx]
+	if arg2.lower() == "onos":
+	  MonitoringByOnos = True
+	  idx = idx + 1
       start_argv_index = idx
     elif arg1 == "-f":
       if idx >= len(sys.argv):
@@ -476,24 +576,8 @@
     idx = idx + 1
 
   #
-  # Do the work: install and/or periodically monitor each flow
-  #
-  while True:
-    idx = 0
-    while idx < len(parsed_args):
-      last_data_path = last_data_paths[idx]
-      my_flow_id = parsed_args[idx]['my_flow_id']
-      data_path = compute_data_path(parsed_args[idx])
-      if data_path != last_data_path:
-	print_data_path(data_path)
-	if len(last_data_path) > 0:
-	  delete_flow_path(my_flow_id)
-	if len(data_path) > 0:
-	  flow_path = compute_flow_path(parsed_args[idx], data_path)
-	  add_flow_path(flow_path)
-	last_data_paths[idx] = copy.deepcopy(data_path)
-      idx = idx + 1
+  if MonitoringByOnos == True:
+    exec_monitoring_by_onos(parsed_args)
+  else:
+    exec_processing_by_script(parsed_args)
 
-    if MonitoringEnabled != True:
-      break
-    time.sleep(1)