Merge branch 'master' of github.com:OPENNETWORKINGLAB/ONOS
diff --git a/cluster-mgmt/template/onsdemo_core.py b/cluster-mgmt/template/onsdemo_core.py
index e62ae77..b9da603 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='00:00:00:16:97:08:9a:46')
-        sw2 = self.addSwitch('sw2', dpid='00:00:00:00:ba:5e:ba:11')
-        sw3 = self.addSwitch('sw3', dpid='00:00:00:08:a2:08:f9:01')
-        sw4 = self.addSwitch('sw4', dpid='00:00:00:00:00:00:ba:12')
-        sw5 = self.addSwitch('sw5', dpid='00:00:00:00:ba:5e:ba:13')
-        sw6 = self.addSwitch('sw6', dpid='00:00:20:4e:7f:51:8a:35')
+        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')
 
         host1 = self.addHost( 'host1' )
         host2 = self.addHost( 'host2' )
@@ -88,6 +88,7 @@
         self.addLink( sw3, sw6 )
         self.addLink( sw4, sw5 )
         self.addLink( sw5, sw6 )
+        self.addLink( sw4, sw6 )
 
         self.addLink( root1, host1 )
         self.addLink( root2, host2 )
diff --git a/scripts/iperf b/scripts/iperf
new file mode 100755
index 0000000..8f518b9
--- /dev/null
+++ b/scripts/iperf
Binary files differ
diff --git a/scripts/showdpid.sh b/scripts/showdpid.sh
index db0adbc..1dff291 100755
--- a/scripts/showdpid.sh
+++ b/scripts/showdpid.sh
@@ -1,6 +1,7 @@
 #! /bin/bash
 controller=""
-switches=`ifconfig -a | grep sw |grep -v eth | awk '{print $1}'`
+#switches=`ifconfig -a | grep sw |grep -v eth | awk '{print $1}'`
+switches=`sudo ovs-vsctl list-br`
 
 function host2ip (){
    ip=`grep $1 /etc/hosts |grep -v "ip6"|  awk '{print $1}'`
diff --git a/scripts/showflow.sh b/scripts/showflow.sh
index 5b6fb34..15824d7 100755
--- a/scripts/showflow.sh
+++ b/scripts/showflow.sh
@@ -1,27 +1,19 @@
 #! /bin/bash
 controller=""
-switches=`ifconfig -a | grep sw |grep -v eth | awk '{print $1}'`
+switches=`sudo ovs-vsctl list-br`
 
 function host2ip (){
    ip=`grep $1 /etc/hosts |grep -v "ip6"|  awk '{print $1}'`
    echo $ip
 }
 
-function cdpid (){
-#    dpid=echo $1 | awk '{printf("%s%s:%s%s:%s%s:%s%s:%s%s:%s%s:%s%s:%s%s",$1[0],$1[1],$1[2],$1[3],$1[4],$1[5],$1[6],$1[7],$1[8],$1[9],$1[10],$1[11],$1[12],$1[13],$1[14],$1[15])}'
-    dpid=`echo $1 | awk '{printf("%s\n",$0[0])}'`
-}
-
 dpids=()
 for s in $switches; do
-#    echo -n "$s : "
     i=`sudo ovs-ofctl  show  $s |grep dpid | awk -F ":" '{print $4}'`
     dpids+=($i)
 done
 ((j=0))
 for s in $switches; do
-    id=`cdpid ${dpids[$j]}`
-    echo id
-#    sudo ovs-ofctl  dump-flows  $s |grep cookie| awk -vsw=$s -vdpid=${dpids[$j]} '{printf("%s %s %s\n",sw,dpid,$0)}'
+    sudo ovs-ofctl  dump-flows  $s |grep cookie| awk -vsw=$s -vdpid=${dpids[$j]} '{printf("%s dpid=%s %s\n",sw,dpid,$0)}'
     ((j ++ ))
 done
diff --git a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
index 71b6593..587b3c2 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -205,6 +205,36 @@
 
 		@Adjacency(label="flow", direction=Direction.IN)
 		public void removeFlowEntry(final IFlowEntry flowEntry);
+
+		@Property("matchEthernetFrameType")
+		public Short getMatchEthernetFrameType();
+
+		@Property("matchEthernetFrameType")
+		public void setMatchEthernetFrameType(Short matchEthernetFrameType);
+
+		@Property("matchSrcMac")
+		public String getMatchSrcMac();
+
+		@Property("matchSrcMac")
+		public void setMatchSrcMac(String matchSrcMac);
+
+		@Property("matchDstMac")
+		public String getMatchDstMac();
+
+		@Property("matchDstMac")
+		public void setMatchDstMac(String matchDstMac);
+
+		@Property("matchSrcIPv4Net")
+		public String getMatchSrcIPv4Net();
+
+		@Property("matchSrcIPv4Net")
+		public void setMatchSrcIPv4Net(String matchSrcIPv4Net);
+
+		@Property("matchDstIPv4Net")
+		public String getMatchDstIPv4Net();
+
+		@Property("matchDstIPv4Net")
+		public void setMatchDstIPv4Net(String matchDstIPv4Net);
 		
 		@JsonIgnore
 		@GremlinGroovy("_().in('flow').out('switch')")
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index d1eae4d..098e02f 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -279,7 +279,7 @@
 
 		//
 		// Fetch all Flow Entries and select only my Flow Entries
-		// that need to be undated into the switches.
+		// that need to be updated into the switches.
 		//
 		Iterable<IFlowEntry> allFlowEntries =
 		    conn.utils().getAllFlowEntries(conn);
@@ -322,13 +322,15 @@
 		boolean processed_measurement_flow = false;
 		for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
 		    IFlowEntry flowEntryObj = entry.getValue();
+		    IFlowPath flowObj =
+			conn.utils().getFlowPathByFlowEntry(conn,
+							    flowEntryObj);
+		    if (flowObj == null)
+			continue;		// Should NOT happen
+
 		    // Code for measurement purpose
 		    {
-			IFlowPath flowObj =
-			    conn.utils().getFlowPathByFlowEntry(conn,
-								flowEntryObj);
-			if ((flowObj != null) &&
-			    flowObj.getFlowId().equals(measurementFlowIdStr)) {
+			if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
 			    processed_measurement_flow = true;
 			}
 		    }
@@ -369,34 +371,54 @@
 		    }
 
 		    //
-		    // Fetch the match conditions
+		    // Fetch the match conditions.
+		    //
+		    // NOTE: The Flow matching conditions common for all
+		    // Flow Entries are used ONLY if a Flow Entry does NOT
+		    // have the corresponding matching condition set.
 		    //
 		    OFMatch match = new OFMatch();
 		    match.setWildcards(OFMatch.OFPFW_ALL);
+		    //
 		    Short matchInPort = flowEntryObj.getMatchInPort();
 		    if (matchInPort != null) {
 			match.setInputPort(matchInPort);
 			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
 		    }
+		    //
 		    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+		    if (matchEthernetFrameType == null)
+			matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
 		    if (matchEthernetFrameType != null) {
 			match.setDataLayerType(matchEthernetFrameType);
 			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
 		    }
+		    //
 		    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+		    if (matchSrcIPv4Net == null)
+			matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
 		    if (matchSrcIPv4Net != null) {
 			match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
 		    }
+		    //
 		    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+		    if (matchDstIPv4Net == null)
+			matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
 		    if (matchDstIPv4Net != null) {
 			match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
 		    }
+		    //
 		    String matchSrcMac = flowEntryObj.getMatchSrcMac();
+		    if (matchSrcMac == null)
+			matchSrcMac = flowObj.getMatchSrcMac();
 		    if (matchSrcMac != null) {
 			match.setDataLayerSource(matchSrcMac);
 			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
 		    }
+		    //
 		    String matchDstMac = flowEntryObj.getMatchDstMac();
+		    if (matchDstMac == null)
+			matchDstMac = flowObj.getMatchDstMac();
 		    if (matchDstMac != null) {
 			match.setDataLayerDestination(matchDstMac);
 			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
@@ -748,12 +770,32 @@
 	// - flowPath.installerId()
 	// - flowPath.dataPath().srcPort()
 	// - flowPath.dataPath().dstPort()
+	// - flowPath.matchEthernetFrameType()
+	// - flowPath.matchSrcIPv4Net()
+	// - flowPath.matchDstIPv4Net()
+	// - flowPath.matchSrcMac()
+	// - flowPath.matchDstMac()
 	//
 	flowObj.setInstallerId(flowPath.installerId().toString());
 	flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
 	flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
 	flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
 	flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
+	if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
+	    flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
+	}
+	if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
+	    flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
+	}
+	if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
+	    flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
+	}
+	if (flowPath.flowEntryMatch().matchSrcMac()) {
+	    flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
+	}
+	if (flowPath.flowEntryMatch().matchDstMac()) {
+	    flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
+	}
 
 	if (dataPathSummaryStr != null) {
 	    flowObj.setDataPathSummary(dataPathSummaryStr);
@@ -1151,6 +1193,7 @@
 		Collections.sort(allFlows);
 		
 		for (FlowPath flow : allFlows) {
+		    flow.setFlowEntryMatch(null);
 			
 			// start from desired flowId
 			//if (flow.flowId().value() < flowId.value()) {
@@ -1253,6 +1296,28 @@
 	flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
 	flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
 	flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
+	//
+	// Extract the match conditions common for all Flow Entries
+	//
+	{
+	    FlowEntryMatch match = new FlowEntryMatch();
+	    Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
+	    if (matchEthernetFrameType != null)
+		match.enableEthernetFrameType(matchEthernetFrameType);
+	    String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
+	    if (matchSrcIPv4Net != null)
+		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	    String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
+	    if (matchDstIPv4Net != null)
+		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	    String matchSrcMac = flowObj.getMatchSrcMac();
+	    if (matchSrcMac != null)
+		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	    String matchDstMac = flowObj.getMatchDstMac();
+	    if (matchDstMac != null)
+		match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	    flowPath.setFlowEntryMatch(match);
+	}
 
 	//
 	// Extract all Flow Entries
@@ -1325,11 +1390,7 @@
     /**
      * Add and maintain a shortest-path flow.
      *
-     * NOTE: The Flow Path argument does NOT contain all flow entries.
-     * Instead, it contains a single dummy flow entry that is used to
-     * store the matching condition(s).
-     * That entry is replaced by the appropriate entries from the
-     * internally performed shortest-path computation.
+     * NOTE: The Flow Path argument does NOT contain flow entries.
      *
      * @param flowPath the Flow Path with the endpoints and the match
      * conditions to install.
@@ -1352,11 +1413,6 @@
 	    dataPath.setDstPort(flowPath.dataPath().dstPort());
 	}
 
-	FlowEntryMatch userFlowEntryMatch = null;
-	if (! flowPath.dataPath().flowEntries().isEmpty()) {
-	    userFlowEntryMatch = flowPath.dataPath().flowEntries().get(0).flowEntryMatch();
-	}
-
 	// Compute the Data Path summary
 	dataPathSummaryStr = dataPath.dataPathSummary();
 
@@ -1366,11 +1422,7 @@
 	//
 	for (FlowEntry flowEntry : dataPath.flowEntries()) {
 	    // Set the incoming port matching
-	    FlowEntryMatch flowEntryMatch = null;
-	    if (userFlowEntryMatch != null)
-		flowEntryMatch = new FlowEntryMatch(userFlowEntryMatch);
-	    else
-		flowEntryMatch = new FlowEntryMatch();
+	    FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
 	    flowEntry.setFlowEntryMatch(flowEntryMatch);
 	    flowEntryMatch.enableInPort(flowEntry.inPort());
 
@@ -1392,6 +1444,7 @@
 	computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
 	computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
 	computedFlowPath.setDataPath(dataPath);
+	computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
 
 	FlowId flowId = new FlowId();
 	if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
@@ -1527,9 +1580,9 @@
 		IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
 		if (mySwitch == null) {
 		    // Not my switch
-		    installRemoteFlowEntry(flowEntry);
+		    installRemoteFlowEntry(flowPath, flowEntry);
 		} else {
-		    installFlowEntry(mySwitch, flowEntry);
+		    installFlowEntry(mySwitch, flowPath, flowEntry);
 		}
 	    }
 
@@ -1553,7 +1606,7 @@
 		IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
 		if (mySwitch == null) {
 		    // Not my switch
-		    installRemoteFlowEntry(flowEntry);
+		    installRemoteFlowEntry(addedFlowPath, flowEntry);
 		    continue;
 		}
 
@@ -1574,7 +1627,7 @@
 		    continue;
 		}
 		// Update the Flow Entry Switch State in the Network MAP
-		if (installFlowEntry(mySwitch, flowEntry)) {
+		if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
 		    flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
 		}
 	    }
@@ -1678,11 +1731,13 @@
      * Install a Flow Entry on a switch.
      *
      * @param mySwitch the switch to install the Flow Entry into.
+     * @param flowPath the flow path for the flow entry to install.
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
     @Override
-    public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
+    public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
+				    FlowEntry flowEntry) {
 	//
 	// Create the OpenFlow Flow Modification Entry to push
 	//
@@ -1706,35 +1761,67 @@
 	}
 
 	//
-	// Fetch the match conditions
+	// Fetch the match conditions.
+	//
+	// NOTE: The Flow matching conditions common for all Flow Entries are
+	// used ONLY if a Flow Entry does NOT have the corresponding matching
+	// condition set.
 	//
 	OFMatch match = new OFMatch();
 	match.setWildcards(OFMatch.OFPFW_ALL);
-	Port matchInPort = flowEntry.flowEntryMatch().inPort();
+	FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
+	FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
+
+	// Match the Incoming Port
+	Port matchInPort = flowEntryMatch.inPort();
 	if (matchInPort != null) {
 	    match.setInputPort(matchInPort.value());
 	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
 	}
-	Short matchEthernetFrameType =
-	    flowEntry.flowEntryMatch().ethernetFrameType();
+
+	// Match the Ethernet Frame Type
+	Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
+	if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
+	    matchEthernetFrameType = flowPathMatch.ethernetFrameType();
+	}
 	if (matchEthernetFrameType != null) {
 	    match.setDataLayerType(matchEthernetFrameType);
 	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
 	}
-	IPv4Net matchSrcIPv4Net = flowEntry.flowEntryMatch().srcIPv4Net();
+
+	// Match the Source IPv4 Network prefix
+	IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
+	if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
+	    matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
+	}
 	if (matchSrcIPv4Net != null) {
 	    match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
 	}
-	IPv4Net matchDstIPv4Net = flowEntry.flowEntryMatch().dstIPv4Net();
+
+	// Natch the Destination IPv4 Network prefix
+	IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
+	if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
+	    matchDstIPv4Net = flowPathMatch.dstIPv4Net();
+	}
 	if (matchDstIPv4Net != null) {
 	    match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
 	}
-	MACAddress matchSrcMac = flowEntry.flowEntryMatch().srcMac();
+
+	// Match the Source MAC address
+	MACAddress matchSrcMac = flowEntryMatch.srcMac();
+	if ((matchSrcMac == null) && (flowPathMatch != null)) {
+	    matchSrcMac = flowPathMatch.srcMac();
+	}
 	if (matchSrcMac != null) {
 	    match.setDataLayerSource(matchSrcMac.toString());
 	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
 	}
-	MACAddress matchDstMac = flowEntry.flowEntryMatch().dstMac();
+
+	// Match the Destination MAC address
+	MACAddress matchDstMac = flowEntryMatch.dstMac();
+	if ((matchDstMac == null) && (flowPathMatch != null)) {
+	    matchDstMac = flowPathMatch.dstMac();
+	}
 	if (matchDstMac != null) {
 	    match.setDataLayerDestination(matchDstMac.toString());
 	    match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
@@ -1799,16 +1886,18 @@
      * Remove a Flow Entry from a switch.
      *
      * @param mySwitch the switch to remove the Flow Entry from.
+     * @param flowPath the flow path for the flow entry to remove.
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
     @Override
-    public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry) {
+    public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
+				   FlowEntry flowEntry) {
 	//
 	// The installFlowEntry() method implements both installation
 	// and removal of flow entries.
 	//
-	return (installFlowEntry(mySwitch, flowEntry));
+	return (installFlowEntry(mySwitch, flowPath, flowEntry));
     }
 
     /**
@@ -1818,11 +1907,13 @@
      * - For now it will make a REST call to the remote controller.
      * - Internally, it needs to know the name of the remote controller.
      *
+     * @param flowPath the flow path for the flow entry to install.
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
     @Override
-    public boolean installRemoteFlowEntry(FlowEntry flowEntry) {
+    public boolean installRemoteFlowEntry(FlowPath flowPath,
+					  FlowEntry flowEntry) {
 	// TODO: We need it now: Jono
 	//  - For now it will make a REST call to the remote controller.
 	//  - Internally, it needs to know the name of the remote controller.
@@ -1832,15 +1923,17 @@
     /**
      * Remove a flow entry on a remote controller.
      *
+     * @param flowPath the flow path for the flow entry to remove.
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
     @Override
-    public boolean removeRemoteFlowEntry(FlowEntry flowEntry) {
+    public boolean removeRemoteFlowEntry(FlowPath flowPath,
+					 FlowEntry flowEntry) {
 	//
 	// The installRemoteFlowEntry() method implements both installation
 	// and removal of flow entries.
 	//
-	return (installRemoteFlowEntry(flowEntry));
+	return (installRemoteFlowEntry(flowPath, flowEntry));
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java b/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java
index 964eff1..585fc36 100644
--- a/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java
+++ b/src/main/java/net/floodlightcontroller/onoslistener/OnosPublisher.java
@@ -95,8 +95,8 @@
 				if (controller == null) {
 					log.debug("request Control to set inactive sw {}", HexString.toHexString(dpid));
 					registryService.requestControl(dpid, new SwitchCleanup());
-				} else {
-					log.debug("sw {} is controlled by controller: {}",HexString.toHexString(dpid),controller);
+				//} else {
+				//	log.debug("sw {} is controlled by controller: {}",HexString.toHexString(dpid),controller);
 				}
 			} catch (NumberFormatException e) {
 				// TODO Auto-generated catch block
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntry.java b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
index 2e61636..3e29c78 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowEntry.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
@@ -219,6 +219,8 @@
     /**
      * Get the Switch incoming port.
      *
+     * Used only when the entry is used to return Shortest Path computation.
+     *
      * @return the Switch incoming port.
      */
     @JsonProperty("inPort")
@@ -227,6 +229,8 @@
     /**
      * Set the Switch incoming port.
      *
+     * Used only when the entry is used to return Shortest Path computation.
+     *
      * @param inPort the Switch incoming port to set.
      */
     @JsonProperty("inPort")
@@ -237,6 +241,8 @@
     /**
      * Get the Switch outgoing port.
      *
+     * Used only when the entry is used to return Shortest Path computation.
+     *
      * @return the Switch outgoing port.
      */
     @JsonProperty("outPort")
@@ -245,6 +251,8 @@
     /**
      * Set the Switch outgoing port.
      *
+     * Used only when the entry is used to return Shortest Path computation.
+     *
      * @param outPort the Switch outgoing port to set.
      */
     @JsonProperty("outPort")
diff --git a/src/main/java/net/floodlightcontroller/util/FlowPath.java b/src/main/java/net/floodlightcontroller/util/FlowPath.java
index f4c25c2..b171b88 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowPath.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowPath.java
@@ -6,6 +6,7 @@
 import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
 import net.floodlightcontroller.util.CallerId;
 import net.floodlightcontroller.util.DataPath;
+import net.floodlightcontroller.util.FlowEntryMatch;
 import net.floodlightcontroller.util.FlowId;
 
 import org.codehaus.jackson.annotate.JsonProperty;
@@ -17,6 +18,8 @@
     private FlowId flowId;		// The Flow ID
     private CallerId installerId;	// The Caller ID of the path installer
     private DataPath dataPath;		// The data path
+    private FlowEntryMatch flowEntryMatch; // Common Flow Entry Match for all
+					// Flow Entries
 
     /**
      * Default constructor.
@@ -24,7 +27,7 @@
     public FlowPath() {
 	dataPath = new DataPath();
     }
-    
+
     /**
      * Constructor to instantiate from object in Network Map
      */
@@ -36,6 +39,28 @@
     	this.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
     	this.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
     	this.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
+	//
+	// Extract the match conditions that are common for all Flow Entries
+	//
+	{
+    	    FlowEntryMatch match = new FlowEntryMatch();
+    	    Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
+    	    if (matchEthernetFrameType != null)
+    		match.enableEthernetFrameType(matchEthernetFrameType);
+    	    String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
+    	    if (matchSrcIPv4Net != null)
+    		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+    	    String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
+    	    if (matchDstIPv4Net != null)
+    		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+    	    String matchSrcMac = flowObj.getMatchSrcMac();
+    	    if (matchSrcMac != null)
+    		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+    	    String matchDstMac = flowObj.getMatchDstMac();
+    	    if (matchDstMac != null)
+    		match.enableDstMac(MACAddress.valueOf(matchDstMac));
+    	    this.setFlowEntryMatch(match);
+	}
 
     	//
     	// Extract all Flow Entries
@@ -149,6 +174,25 @@
     }
 
     /**
+     * Get the flow path's match conditions common for all Flow Entries.
+     *
+     * @return the flow path's match conditions common for all Flow Entries.
+     */
+    @JsonProperty("flowEntryMatch")
+    public FlowEntryMatch flowEntryMatch() { return flowEntryMatch; }
+
+    /**
+     * Set the flow path's match conditions common for all Flow Entries.
+     *
+     * @param flowEntryMatch the flow path's match conditions common for all
+     * Flow Entries.
+     */
+    @JsonProperty("flowEntryMatch")
+    public void setFlowEntryMatch(FlowEntryMatch flowEntryMatch) {
+	this.flowEntryMatch = flowEntryMatch;
+    }
+
+    /**
      * Convert the flow path to a string.
      *
      * The string has the following form:
@@ -160,7 +204,10 @@
     public String toString() {
 	String ret = "[flowId=" + this.flowId.toString();
 	ret += " installerId=" + this.installerId.toString();
-	ret += " dataPath=" + this.dataPath.toString();
+	if (dataPath != null)
+	    ret += " dataPath=" + this.dataPath.toString();
+	if (flowEntryMatch != null)
+	    ret += " flowEntryMatch=" + this.flowEntryMatch.toString();
 	ret += "]";
 	return ret;
     }
diff --git a/src/main/java/net/onrc/onos/flow/IFlowManager.java b/src/main/java/net/onrc/onos/flow/IFlowManager.java
index d163760..743f8fb 100644
--- a/src/main/java/net/onrc/onos/flow/IFlowManager.java
+++ b/src/main/java/net/onrc/onos/flow/IFlowManager.java
@@ -84,19 +84,23 @@
      * Install a Flow Entry on a switch.
      *
      * @param mySwitch the switch to install the Flow Entry into.
+     * @param flowPath the flow path for the flow entry to install.
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    public boolean installFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry);
+    public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
+				    FlowEntry flowEntry);
 
     /**
      * Remove a Flow Entry from a switch.
      *
      * @param mySwitch the switch to remove the Flow Entry from.
+     * @param flowPath the flow path for the flow entry to remove.
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
-    public boolean removeFlowEntry(IOFSwitch mySwitch, FlowEntry flowEntry);
+    public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
+				   FlowEntry flowEntry);
 
     /**
      * Install a Flow Entry on a remote controller.
@@ -105,16 +109,20 @@
      * - For now it will make a REST call to the remote controller.
      * - Internally, it needs to know the name of the remote controller.
      *
+     * @param flowPath the flow path for the flow entry to install.
      * @param flowEntry the flow entry to install.
      * @return true on success, otherwise false.
      */
-    public boolean installRemoteFlowEntry(FlowEntry flowEntry);
+    public boolean installRemoteFlowEntry(FlowPath flowPath,
+					  FlowEntry flowEntry);
 
     /**
      * Remove a flow entry on a remote controller.
      *
+     * @param flowPath the flow path for the flow entry to remove.
      * @param flowEntry the flow entry to remove.
      * @return true on success, otherwise false.
      */
-    public boolean removeRemoteFlowEntry(FlowEntry flowEntry);
+    public boolean removeRemoteFlowEntry(FlowPath flowPath,
+					 FlowEntry flowEntry);
 }
diff --git a/web/add_flow.py b/web/add_flow.py
index 5a248eb..4f502f6 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -340,6 +340,9 @@
   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
   #
@@ -393,7 +396,6 @@
     dst_port = {}
     src_switch_port = {}
     dst_switch_port = {}
-    flow_entry = {}
     flow_entries = []
 
     src_dpid['value'] = parsed_args[idx]['my_src_dpid']
@@ -404,9 +406,6 @@
     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)
diff --git a/web/get_flow.py b/web/get_flow.py
index 5704457..033176d 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -42,6 +42,61 @@
   dstPort = parsedResult['dataPath']['dstPort']['port']['value']
 
   print "FlowPath: (flowId = %s installerId = %s src = %s/%s dst = %s/%s)" % (flowId, installerId, srcSwitch, srcPort, dstSwitch, dstPort)
+  match = parsedResult['flowEntryMatch'];
+  #
+  # Print the common conditions
+  #
+  if match == None:
+    print "   Match: %s" % (match)
+  else:
+    # inPort = match['inPort']
+    # matchInPort = match['matchInPort']
+    srcMac = match['srcMac']
+    matchSrcMac = match['matchSrcMac']
+    dstMac = match['dstMac']
+    matchDstMac = match['matchDstMac']
+    vlanId = match['vlanId']
+    matchVlanId = match['matchVlanId']
+    vlanPriority = match['vlanPriority']
+    matchVlanPriority = match['matchVlanPriority']
+    ethernetFrameType = match['ethernetFrameType']
+    matchEthernetFrameType = match['matchEthernetFrameType']
+    ipToS = match['ipToS']
+    matchIpToS = match['matchIpToS']
+    ipProto = match['ipProto']
+    matchIpProto = match['matchIpProto']
+    srcIPv4Net = match['srcIPv4Net']
+    matchSrcIPv4Net = match['matchSrcIPv4Net']
+    dstIPv4Net = match['dstIPv4Net']
+    matchDstIPv4Net = match['matchDstIPv4Net']
+    srcTcpUdpPort = match['srcTcpUdpPort']
+    matchSrcTcpUdpPort = match['matchSrcTcpUdpPort']
+    dstTcpUdpPort = match['dstTcpUdpPort']
+    matchDstTcpUdpPort = match['matchDstTcpUdpPort']
+    # if matchInPort == True:
+    #  print "    inPort: %s" % inPort['value']
+    if matchSrcMac == True:
+      print "    srcMac: %s" % srcMac['value']
+    if matchDstMac == True:
+      print "    dstMac: %s" % dstMac['value']
+    if matchVlanId == True:
+      print "    vlanId: %s" % vlanId
+    if matchVlanPriority == True:
+      print "    vlanPriority: %s" % vlanPriority
+    if matchEthernetFrameType == True:
+      print "    ethernetFrameType: %s" % hex(ethernetFrameType)
+    if matchIpToS == True:
+      print "    ipToS: %s" % ipToS
+    if matchIpProto == True:
+      print "    ipProto: %s" % ipProto
+    if matchSrcIPv4Net == True:
+      print "    srcIPv4Net: %s" % srcIPv4Net['value']
+    if matchDstIPv4Net == True:
+      print "    dstIPv4Net: %s" % dstIPv4Net['value']
+    if matchSrcTcpUdpPort == True:
+      print "    srcTcpUdpPort: %s" % srcTcpUdpPort
+    if matchDstTcpUdpPort == True:
+      print "    dstTcpUdpPort: %s" % dstTcpUdpPort
 
   for f in parsedResult['dataPath']['flowEntries']:
     flowEntryId = f['flowEntryId']
diff --git a/web/pingall.py b/web/pingall.py
index f4f10c2..0643cb9 100755
--- a/web/pingall.py
+++ b/web/pingall.py
@@ -1,11 +1,16 @@
 #! /usr/bin/env python
 import sys
+import time
 import os
 
-hosts=['onosgui1', 'onosgui2', 'onosgui3', 'onosgui4', 'onosgui5', 'onosgui6', 'onosgui7', 'onosgui8']
+hosts=['onosdevz1', 'onosdevz2', 'onosdevz3', 'onosdevz4', 'onosdevz5', 'onosdevz6', 'onosdevz7', 'onosdevz8']
 filename = sys.argv[1]
 
+ping_cnt=3
+wait=ping_cnt
+
 f = open(filename, 'r')
+nr_ping = 0
 for line in f:
   if line[0] != "#":
     fid=int(line.strip().split()[0])
@@ -15,10 +20,34 @@
     dst_nwid=int(dst_dpid.split(':')[-2], 16)
     src_hostid=int(src_dpid.split(':')[-1], 16)
     dst_hostid=int(dst_dpid.split(':')[-1], 16)
-#    cmd="ssh %s \'ssh -o StrictHostKeyChecking=no 1.1.%d.1 ping -c 10 -W 1 192.168.%d.%d\' > /tmp/ping.%d 2>&1 &" % (hosts[src_nwid-1], src_hostid, dst_nwid, dst_hostid,fid)
-#    cmd="ssh %s \'ssh -o StrictHostKeyChecking=no 1.1.%d.1 arp 193.168.%d.%d; ping -c 10 -W 1 192.168.%d.%d\' > /tmp/ping.%d 2>&1 &" % (hosts[src_nwid-1], src_hostid, dst_nwid, dst_hostid, dst_nwid, dst_hostid,fid)
-    cmd="ssh %s \'ssh -o StrictHostKeyChecking=no 1.1.%d.1 ping -c 10 -W 1 192.168.%d.%d\' > /tmp/ping.%d 2>&1 &" % (hosts[src_nwid-1], src_hostid, dst_nwid, dst_hostid,fid)
-    print cmd
+    cmd="echo \"192.168.%d.%d -> 192.168.%d.%d\" > /tmp/ping.%d" % (src_nwid, src_hostid, dst_nwid, dst_hostid,fid)
+    os.popen(cmd)
+    cmd="ssh %s \'ssh -o StrictHostKeyChecking=no 1.1.%d.1 \'ping -c %d -W 1 192.168.%d.%d\'\' >> /tmp/ping.%d 2>&1 &" % (hosts[src_nwid-1], src_hostid, ping_cnt, dst_nwid, dst_hostid,fid)
+#    print cmd
     result = os.popen(cmd).read()
+    nr_ping = nr_ping + 1
+
+print "waiting for ping(s) to finish (%d sec)" % (wait)
+time.sleep(wait)
+cmd="cat /tmp/ping.* | grep loss |wc -l"
+while 1:
+  result = int(os.popen(cmd).read())
+  if result == nr_ping:
+    break
+
+cmd='cat /tmp/ping.* | grep " 0% packet loss" |wc -l'
+result = int(os.popen(cmd).read())
+if result != nr_ping:
+  print "fail: %d ping(s) failed (out of %d)" % (nr_ping - result, nr_ping)
+else:
+  print "success: all %d ping(s) got through" % (result)
+
+for i in range(nr_ping):
+  cmd="cat /tmp/ping.%d | grep loss | awk '{print $6}'" % (i+1)
+  cmd2="cat /tmp/ping.%d | head -n 1" % (i+1)
+  result = os.popen(cmd).read().strip()
+  result2 = os.popen(cmd2).read().strip()
+  if result != "0%":
+    print "flow # %d fail (%s)" % (i+1, result2)
 
 f.close()