Merge branch 'master' of 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 8788aa7..c70ab16 100644
--- a/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
+++ b/src/main/java/net/floodlightcontroller/core/INetMapTopologyObjects.java
@@ -193,18 +193,6 @@
 		@Property("switch_dpid")
 		public void setSwitchDpid(String switchDpid);
 
-		@Property("in_port")
-		public Short getInPort();
-
-		@Property("in_port")
-		public void setInPort(Short inPort);
-
-		@Property("out_port")
-		public Short getOutPort();
-
-		@Property("out_port")
-		public void setOutPort(Short outPort);
-
 		@Property("user_state")
 		public String getUserState();
 
@@ -228,5 +216,47 @@
 
 		@Property("error_state_code")
 		public void setErrorStateCode(String errorStateCode);
+
+		@Property("matchInPort")
+		public Short getMatchInPort();
+
+		@Property("matchInPort")
+		public void setMatchInPort(Short matchInPort);
+
+		@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);
+
+		@Property("actionOutput")
+		public Short getActionOutput();
+
+		@Property("actionOutput")
+		public void setActionOutput(Short actionOutput);
 	}
 }
diff --git a/src/main/java/net/floodlightcontroller/core/internal/Controller.java b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
index 3e657d1..d4a44fc 100644
--- a/src/main/java/net/floodlightcontroller/core/internal/Controller.java
+++ b/src/main/java/net/floodlightcontroller/core/internal/Controller.java
@@ -489,36 +489,25 @@
 				
 				Role role = null;
 				
-				if (sw.getRole() == null){
-					if (hasControl){
-						role = Role.MASTER;
-					}
-					else {
-						role = Role.SLAVE;
-					}
-				}
-				else if (hasControl && sw.getRole() == Role.SLAVE) {
-					// Send a MASTER role request to the switch.
-					// If this is the first role request, 
-                    // this is a probe that we'll use to determine if the switch
-                    // actually supports the role request message. If it does we'll
-                    // get back a role reply message. If it doesn't we'll get back an
-                    // OFError message. 
-                    // If role is MASTER we will promote switch to active
-                    // list when we receive the switch's role reply messages
+				/*
+				 * issue #229
+				 * Cannot rely on sw.getRole() as it can be behind due to pending
+				 * role changes in the queue. Just submit it and late the RoleChanger
+				 * handle duplicates.
+				 */
+
+				if (hasControl){
 					role = Role.MASTER;
 				}
-				else if (!hasControl && sw.getRole() == Role.MASTER) {
-					//Send a SLAVE role request to the switch
+				else {
 					role = Role.SLAVE;
 				}
-				
-				if (role != null) {
-					log.debug("Sending role request {} msg to {}", role, sw);
-	                Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
-	                swList.add(sw);
-	                roleChanger.submitRequest(swList, role);
-				}
+
+				log.debug("Sending role request {} msg to {}", role, sw);
+				Collection<OFSwitchImpl> swList = new ArrayList<OFSwitchImpl>(1);
+				swList.add(sw);
+				roleChanger.submitRequest(swList, role);
+
 			}
 			
 		}
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index a5f759c..838c3ed 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -29,11 +29,15 @@
 import net.floodlightcontroller.util.Dpid;
 import net.floodlightcontroller.util.DataPathEndpoints;
 import net.floodlightcontroller.util.FlowEntry;
+import net.floodlightcontroller.util.FlowEntryAction;
 import net.floodlightcontroller.util.FlowEntryId;
+import net.floodlightcontroller.util.FlowEntryMatch;
 import net.floodlightcontroller.util.FlowEntrySwitchState;
 import net.floodlightcontroller.util.FlowEntryUserState;
 import net.floodlightcontroller.util.FlowId;
 import net.floodlightcontroller.util.FlowPath;
+import net.floodlightcontroller.util.IPv4Net;
+import net.floodlightcontroller.util.MACAddress;
 import net.floodlightcontroller.util.OFMessageDamper;
 import net.floodlightcontroller.util.Port;
 import net.onrc.onos.util.GraphDBConnection;
@@ -123,14 +127,54 @@
 			continue;
 		    }
 
+		    //
+		    // Fetch the match conditions
+		    //
 		    OFMatch match = new OFMatch();
-		    match.setInputPort(flowEntryObj.getInPort());
+		    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) {
+			match.setDataLayerType(matchEthernetFrameType);
+			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
+		    }
+		    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+		    if (matchSrcIPv4Net != null) {
+			match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
+		    }
+		    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+		    if (matchDstIPv4Net != null) {
+			match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
+		    }
+		    String matchSrcMac = flowEntryObj.getMatchSrcMac();
+		    if (matchSrcMac != null) {
+			match.setDataLayerSource(matchSrcMac);
+			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
+		    }
+		    String matchDstMac = flowEntryObj.getMatchDstMac();
+		    if (matchDstMac != null) {
+			match.setDataLayerDestination(matchDstMac);
+			match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
+		    }
+		    log.debug("PAVPAV {}:", match.toString());
 
-		    OFActionOutput action = new OFActionOutput();
-		    action.setMaxLength((short)0xffff);
-		    action.setPort(flowEntryObj.getOutPort());
+
+		    //
+		    // Fetch the actions
+		    //
 		    List<OFAction> actions = new ArrayList<OFAction>();
-		    actions.add(action);
+		    Short actionOutputPort = flowEntryObj.getActionOutput();
+		    if (actionOutputPort != null) {
+			OFActionOutput action = new OFActionOutput();
+			// XXX: The max length is hard-coded for now
+			action.setMaxLength((short)0xffff);
+			action.setPort(actionOutputPort);
+			actions.add(action);
+		    }
 
 		    fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
 			.setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
@@ -351,15 +395,35 @@
 	    // - flowEntry.flowEntryMatch()
 	    // - flowEntry.flowEntryActions()
 	    // - flowEntry.dpid()
-	    // - flowEntry.inPort()
-	    // - flowEntry.outPort()
 	    // - flowEntry.flowEntryUserState()
 	    // - flowEntry.flowEntrySwitchState()
 	    // - flowEntry.flowEntryErrorState()
+	    // - flowEntry.matchInPort()
+	    // - flowEntry.matchEthernetFrameType()
+	    // - flowEntry.matchSrcIPv4Net()
+	    // - flowEntry.matchDstIPv4Net()
+	    // - flowEntry.matchSrcMac()
+	    // - flowEntry.matchDstMac()
+	    // - flowEntry.actionOutput()
 	    //
 	    flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
-	    flowEntryObj.setInPort(flowEntry.inPort().value());
-	    flowEntryObj.setOutPort(flowEntry.outPort().value());
+	    if (flowEntry.flowEntryMatch().matchInPort())
+		flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
+	    if (flowEntry.flowEntryMatch().matchEthernetFrameType())
+		flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
+	    if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
+		flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
+	    if (flowEntry.flowEntryMatch().matchDstIPv4Net())
+		flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
+	    if (flowEntry.flowEntryMatch().matchSrcMac())
+		flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
+	    if (flowEntry.flowEntryMatch().matchDstMac())
+		flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
+
+	    for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
+		if (fa.actionOutput() != null)
+		    flowEntryObj.setActionOutput(fa.actionOutput().port().value());
+	    }
 	    // TODO: Hacks with hard-coded state names!
 	    if (found)
 		flowEntryObj.setUserState("FE_USER_MODIFY");
@@ -367,7 +431,7 @@
 		flowEntryObj.setUserState("FE_USER_ADD");
 	    flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
 	    //
-	    // TODO: Take care of the FlowEntryMatch, FlowEntryActions,
+	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
 	    // and FlowEntryErrorState.
 	    //
 
@@ -640,14 +704,49 @@
 	    FlowEntry flowEntry = new FlowEntry();
 	    flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
 	    flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
-	    flowEntry.setInPort(new Port(flowEntryObj.getInPort()));
-	    flowEntry.setOutPort(new Port(flowEntryObj.getOutPort()));
+
+	    //
+	    // Extract the match conditions
+	    //
+	    FlowEntryMatch match = new FlowEntryMatch();
+	    Short matchInPort = flowEntryObj.getMatchInPort();
+	    if (matchInPort != null)
+		match.enableInPort(new Port(matchInPort));
+	    Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
+	    if (matchEthernetFrameType != null)
+		match.enableEthernetFrameType(matchEthernetFrameType);
+	    String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
+	    if (matchSrcIPv4Net != null)
+		match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
+	    String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
+	    if (matchDstIPv4Net != null)
+		match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
+	    String matchSrcMac = flowEntryObj.getMatchSrcMac();
+	    if (matchSrcMac != null)
+		match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
+	    String matchDstMac = flowEntryObj.getMatchDstMac();
+	    if (matchDstMac != null)
+		match.enableDstMac(MACAddress.valueOf(matchDstMac));
+	    flowEntry.setFlowEntryMatch(match);
+
+	    //
+	    // Extract the actions
+	    //
+	    ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+	    Short actionOutputPort = flowEntryObj.getActionOutput();
+	    if (actionOutputPort != null) {
+		FlowEntryAction action = new FlowEntryAction();
+		action.setActionOutput(new Port(actionOutputPort));
+		actions.add(action);
+	    }
+	    flowEntry.setFlowEntryActions(actions);
+
 	    String userState = flowEntryObj.getUserState();
 	    flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
 	    String switchState = flowEntryObj.getSwitchState();
 	    flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
 	    //
-	    // TODO: Take care of the FlowEntryMatch, FlowEntryActions,
+	    // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
 	    // and FlowEntryErrorState.
 	    //
 	    flowPath.dataPath().flowEntries().add(flowEntry);
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntry.java b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
index efab0cf..64c32b4 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowEntry.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntry.java
@@ -1,13 +1,18 @@
 package net.floodlightcontroller.util;
 
+import java.util.ArrayList;
+
 import net.floodlightcontroller.util.Dpid;
-import net.floodlightcontroller.util.FlowEntryActions;
+import net.floodlightcontroller.util.FlowEntryAction;
 import net.floodlightcontroller.util.FlowEntryId;
 import net.floodlightcontroller.util.FlowEntryMatch;
 import net.floodlightcontroller.util.FlowEntrySwitchState;
 import net.floodlightcontroller.util.FlowEntryUserState;
 import net.floodlightcontroller.util.Port;
 
+import net.floodlightcontroller.util.MACAddress;
+import net.floodlightcontroller.util.IPv4;
+
 import org.codehaus.jackson.annotate.JsonProperty;
 
 /**
@@ -19,7 +24,7 @@
 public class FlowEntry {
     private FlowEntryId flowEntryId;		// The Flow Entry ID
     private FlowEntryMatch flowEntryMatch;	// The Flow Entry Match
-    private FlowEntryActions flowEntryActions;	// The Flow Entry Actions
+    private ArrayList<FlowEntryAction> flowEntryActions; // The Flow Entry Actions
     private Dpid dpid;				// The Switch DPID
     private Port inPort;			// The Switch incoming port
     private Port outPort;			// The Switch outgoing port
@@ -32,6 +37,85 @@
      * Default constructor.
      */
     public FlowEntry() {
+	// TODO: Test code
+	/*
+	MACAddress mac = MACAddress.valueOf("01:02:03:04:05:06");
+	IPv4 ipv4 = new IPv4("1.2.3.4");
+	IPv4Net ipv4net = new IPv4Net("5.6.7.0/24");
+
+	flowEntryMatch = new FlowEntryMatch();
+	flowEntryMatch.enableInPort(new Port((short)10));
+	flowEntryMatch.enableSrcMac(mac);
+	flowEntryMatch.enableDstMac(mac);
+	flowEntryMatch.enableVlanId((short)20);
+	flowEntryMatch.enableVlanPriority((byte)30);
+	flowEntryMatch.enableEthernetFrameType((short)40);
+	flowEntryMatch.enableIpToS((byte)50);
+	flowEntryMatch.enableIpProto((byte)60);
+	flowEntryMatch.enableSrcIPv4Net(ipv4net);
+	flowEntryMatch.enableDstIPv4Net(ipv4net);
+	flowEntryMatch.enableSrcTcpUdpPort((short)70);
+	flowEntryMatch.enableDstTcpUdpPort((short)80);
+
+	FlowEntryAction action = null;
+	ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
+
+	action = new FlowEntryAction();
+	action.setActionOutput(new Port((short)12));
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionOutputToController((short)13);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetVlanId((short)14);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetVlanPriority((byte)15);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionStripVlan(true);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetEthernetSrcAddr(mac);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetEthernetDstAddr(mac);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetIPv4SrcAddr(ipv4);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetIPv4DstAddr(ipv4);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetIpToS((byte)16);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetTcpUdpSrcPort((short)17);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionSetTcpUdpDstPort((short)18);
+	actions.add(action);
+
+	action = new FlowEntryAction();
+	action.setActionEnqueue(new Port((short)19), 20);
+	actions.add(action);
+
+	setFlowEntryActions(actions);
+	*/
+
+
 	flowEntryUserState = FlowEntryUserState.FE_USER_UNKNOWN;
 	flowEntrySwitchState = FlowEntrySwitchState.FE_SWITCH_UNKNOWN;
     }
@@ -78,7 +162,9 @@
      * @return the Flow Entry Actions.
      */
     @JsonProperty("flowEntryActions")
-    public FlowEntryActions flowEntryActions() { return flowEntryActions; }
+    public ArrayList<FlowEntryAction> flowEntryActions() {
+	return flowEntryActions;
+    }
 
     /**
      * Set the Flow Entry Actions.
@@ -86,7 +172,7 @@
      * @param flowEntryActions the Flow Entry Actions to set.
      */
     @JsonProperty("flowEntryActions")
-    public void setFlowEntryActions(FlowEntryActions flowEntryActions) {
+    public void setFlowEntryActions(ArrayList<FlowEntryAction> flowEntryActions) {
 	this.flowEntryActions = flowEntryActions;
     }
 
@@ -214,7 +300,8 @@
      * Convert the flow entry to a string.
      *
      * The string has the following form:
-     *  [flowEntryId=XXX flowEntryMatch=XXX flowEntryActions=XXX dpid=XXX
+     *  [flowEntryId=XXX flowEntryMatch=XXX flowEntryAction=XXX
+     *   flowEntryAction=XXX flowEntryAction=XXX dpid=XXX
      *   inPort=XXX outPort=XXX flowEntryUserState=XXX flowEntrySwitchState=XXX
      *   flowEntryErrorState=XXX]
      * @return the flow entry as a string.
@@ -223,7 +310,9 @@
     public String toString() {
 	String ret = "[flowEntryId=" + this.flowEntryId.toString();
 	ret += " flowEntryMatch=" + this.flowEntryMatch.toString();
-	ret += " flowEntryActions=" + this.flowEntryActions.toString();
+	for (FlowEntryAction fa : flowEntryActions) {
+	    ret += " flowEntryAction=" + fa.toString();
+	}
 	ret += " dpid=" + this.dpid.toString();
 	ret += " inPort=" + this.inPort.toString();
 	ret += " outPort=" + this.outPort.toString();
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntryAction.java b/src/main/java/net/floodlightcontroller/util/FlowEntryAction.java
new file mode 100644
index 0000000..1fc1783
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntryAction.java
@@ -0,0 +1,1015 @@
+package net.floodlightcontroller.util;
+
+import net.floodlightcontroller.util.IPv4;
+import net.floodlightcontroller.util.MACAddress;
+import net.floodlightcontroller.util.Port;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+/**
+ * The class representing a single Flow Entry action.
+ *
+ * A set of Flow Entry actions need to be applied to each packet.
+ */
+public class FlowEntryAction {
+    /**
+     * Special action values.
+     *
+     * Those values are taken as-is from the OpenFlow-v1.0.0 specification
+     * (pp 21-22).
+     */
+    public enum ActionValues {
+	ACTION_OUTPUT		((short)0x0),	// Output to switch port
+	ACTION_SET_VLAN_VID	((short)0x1),	// Set the 802.1q VLAN id
+	ACTION_SET_VLAN_PCP	((short)0x2),	// Set the 802.1q priority
+	ACTION_STRIP_VLAN	((short)0x3),	// Strip the 802.1q header
+	ACTION_SET_DL_SRC	((short)0x4),	// Ethernet source address
+	ACTION_SET_DL_DST	((short)0x5),	// Ethernet destination address
+	ACTION_SET_NW_SRC	((short)0x6),	// IP source address
+	ACTION_SET_NW_DST	((short)0x7),	// IP destination address
+	ACTION_SET_NW_TOS	((short)0x8),	// IP ToS (DSCP field, 6 bits)
+	ACTION_SET_TP_SRC	((short)0x9),	// TCP/UDP source port
+	ACTION_SET_TP_DST	((short)0xa),	// TCP/UDP destination port
+	ACTION_ENQUEUE		((short)0xb),	// Output to queue on port
+	ACTION_VENDOR		((short)0xffff); // Vendor-specific
+
+	private final short value;	// The value
+
+	/**
+	 * Constructor for a given value.
+	 *
+	 * @param value the value to use for the initialization.
+	 */
+	private ActionValues(short value) {
+	    this.value = value;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_OUTPUT: Output to switch port.
+     */
+    public class ActionOutput {
+	private Port port;	// Output port
+	private short maxLen;	// Max. length (in bytes) to send to controller
+				// if the port is set to PORT_CONTROLLER
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionOutput() {
+	    this.port = null;
+	    this.maxLen = 0;
+	}
+
+
+	/**
+	 * Constructor for a given output port and maximum length.
+	 *
+	 * @param port the output port to set.
+	 * @param maxLen the maximum length (in bytes) to send to controller
+	 * if the port is set to PORT_CONTROLLER.
+	 */
+	public ActionOutput(Port port, short maxLen) {
+	    this.port = port;
+	    this.maxLen = maxLen;
+	}
+
+	/**
+	 * Constructor for a given output port.
+	 *
+	 * @param port the output port to set.
+	 */
+	public ActionOutput(Port port) {
+	    this.port = port;
+	    this.maxLen = 0;
+	}
+
+	/**
+	 * Get the output port.
+	 *
+	 * @return the output port.
+	 */
+	@JsonProperty("port")
+	public Port port() {
+	    return this.port;
+	}
+
+	/**
+	 * Get the maximum length (in bytes) to send to controller if the
+	 * port is set to PORT_CONTROLLER.
+	 *
+	 * @return the maximum length (in bytes) to send to controller if the
+	 * port is set to PORT_CONTROLLER.
+	 */
+	@JsonProperty("maxLen")
+	public short maxLen() {
+	    return this.maxLen;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX maxLen=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "port=" + port.toString();
+	    ret += " maxLen=" + maxLen;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_SET_VLAN_VID: Set the 802.1q VLAN id
+     */
+    public class ActionSetVlanId {
+	private short vlanId;		// The VLAN ID to set
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionSetVlanId() {
+	    this.vlanId = 0;
+	}
+
+	/**
+	 * Constructor for a given VLAN ID.
+	 *
+	 * @param vlanId the VLAN ID to set.
+	 */
+	public ActionSetVlanId(short vlanId) {
+	    this.vlanId = vlanId;
+	}
+
+	/**
+	 * Get the VLAN ID.
+	 *
+	 * @return the VLAN ID.
+	 */
+	@JsonProperty("vlanId")
+	public short vlanId() {
+	    return this.vlanId;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [vlanId=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "vlanId=" + this.vlanId;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_SET_VLAN_PCP: Set the 802.1q priority
+     */
+    public class ActionSetVlanPriority {
+	private byte vlanPriority;	// The VLAN priority to set
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionSetVlanPriority() {
+	    this.vlanPriority = 0;
+	}
+
+	/**
+	 * Constructor for a given VLAN priority.
+	 *
+	 * @param vlanPriority the VLAN priority to set.
+	 */
+	public ActionSetVlanPriority(byte vlanPriority) {
+	    this.vlanPriority = vlanPriority;
+	}
+
+	/**
+	 * Get the VLAN priority.
+	 *
+	 * @return the VLAN priority.
+	 */
+	@JsonProperty("vlanPriority")
+	public byte vlanPriority() {
+	    return this.vlanPriority;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [vlanPriority=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "vlanPriority=" + this.vlanPriority;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_STRIP_VLAN: Strip the 802.1q header
+     */
+    public class ActionStripVlan {
+	private boolean stripVlan;	// If true, strip the VLAN header
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionStripVlan() {
+	    this.stripVlan = false;
+	}
+
+	/**
+	 * Constructor for a given boolean flag.
+	 *
+	 * @param stripVlan if true, strip the VLAN header.
+	 */
+	public ActionStripVlan(boolean stripVlan) {
+	    this.stripVlan = stripVlan;
+	}
+
+	/**
+	 * Get the boolean flag whether the VLAN header should be stripped.
+	 *
+	 * @return the boolean flag whether the VLAN header should be stripped.
+	 */
+	@JsonProperty("stripVlan")
+	public boolean stripVlan() {
+	    return this.stripVlan;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [stripVlan=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "stripVlan=" + this.stripVlan;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_SET_DL_SRC and ACTION_SET_DL_DST:
+     * Set the Ethernet source/destination address.
+     */
+    public class ActionSetEthernetAddr {
+	private MACAddress addr;	// The MAC address to set
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionSetEthernetAddr() {
+	    this.addr = null;
+	}
+
+	/**
+	 * Constructor for a given MAC address.
+	 *
+	 * @param addr the MAC address to set.
+	 */
+	public ActionSetEthernetAddr(MACAddress addr) {
+	    this.addr = addr;
+	}
+
+	/**
+	 * Get the MAC address.
+	 *
+	 * @return the MAC address.
+	 */
+	@JsonProperty("addr")
+	public MACAddress addr() {
+	    return this.addr;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [addr=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "addr=" + addr.toString();
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_SET_NW_SRC and ACTION_SET_NW_DST:
+     * Set the IPv4 source/destination address.
+     */
+    public class ActionSetIPv4Addr {
+	private IPv4 addr;		// The IPv4 address to set
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionSetIPv4Addr() {
+	    this.addr = null;
+	}
+
+	/**
+	 * Constructor for a given IPv4 address.
+	 *
+	 * @param addr the IPv4 address to set.
+	 */
+	public ActionSetIPv4Addr(IPv4 addr) {
+	    this.addr = addr;
+	}
+
+	/**
+	 * Get the IPv4 address.
+	 *
+	 * @return the IPv4 address.
+	 */
+	@JsonProperty("addr")
+	public IPv4 addr() {
+	    return this.addr;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [addr=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "addr=" + addr.toString();
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_SET_NW_TOS:
+     * Set the IP ToS (DSCP field, 6 bits).
+     */
+    public class ActionSetIpToS {
+	private byte ipToS;	// The IP ToS to set DSCP field, 6 bits)
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionSetIpToS() {
+	    this.ipToS = 0;
+	}
+
+	/**
+	 * Constructor for a given IP ToS (DSCP field, 6 bits).
+	 *
+	 * @param ipToS the IP ToS (DSCP field, 6 bits) to set.
+	 */
+	public ActionSetIpToS(byte ipToS) {
+	    this.ipToS = ipToS;
+	}
+
+	/**
+	 * Get the IP ToS (DSCP field, 6 bits).
+	 *
+	 * @return the IP ToS (DSCP field, 6 bits).
+	 */
+	@JsonProperty("ipToS")
+	public byte ipToS() {
+	    return this.ipToS;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [ipToS=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "ipToS=" + ipToS;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_SET_TP_SRC and ACTION_SET_TP_DST:
+     * Set the TCP/UDP source/destination port.
+     */
+    public class ActionSetTcpUdpPort {
+	private short port;		// The TCP/UDP port to set
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionSetTcpUdpPort() {
+	    this.port = 0;
+	}
+
+	/**
+	 * Constructor for a given TCP/UDP port.
+	 *
+	 * @param port the TCP/UDP port to set.
+	 */
+	public ActionSetTcpUdpPort(short port) {
+	    this.port = port;
+	}
+
+	/**
+	 * Get the TCP/UDP port.
+	 *
+	 * @return the TCP/UDP port.
+	 */
+	@JsonProperty("port")
+	public short port() {
+	    return this.port;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "port=" + port;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    /**
+     * Action structure for ACTION_ENQUEUE: Output to queue on port.
+     */
+    public class ActionEnqueue {
+	private Port port;	// Port that queue belongs. Should
+				// refer to a valid physical port
+				// (i.e. < PORT_MAX) or PORT_IN_PORT
+	private int queueId;	// Where to enqueue the packets
+
+	/**
+	 * Default constructor.
+	 */
+	public ActionEnqueue() {
+	    this.port = null;
+	    this.queueId = 0;
+	}
+
+	/**
+	 * Constructor for a given port and queue ID.
+	 *
+	 * @param port the port to set.
+	 * @param queueId the queue ID on the port.
+	 */
+	public ActionEnqueue(Port port, int queueId) {
+	    this.port = port;
+	    this.queueId = queueId;
+	}
+
+	/**
+	 * Get the port.
+	 *
+	 * @return the port.
+	 */
+	@JsonProperty("port")
+	public Port port() {
+	    return this.port;
+	}
+
+	/**
+	 * Get the queue ID.
+	 *
+	 * @return the queue ID.
+	 */
+	@JsonProperty("queueId")
+	public int queueId() {
+	    return this.queueId;
+	}
+
+	/**
+	 * Convert the action to a string.
+	 *
+	 * The string has the following form:
+	 *  [port=XXX queueId=XXX]
+	 *
+	 * @return the action as a string.
+	 */
+	@Override
+	public String toString() {
+	    String ret = "[";
+	    ret += "port=" + port.toString();
+	    ret += " queueId=" + queueId;
+	    ret += "]";
+
+	    return ret;
+	}
+    }
+
+    private ActionValues actionType;	// The action type
+
+    //
+    // The actions.
+    // NOTE: Only one action should be set.
+    //
+    private ActionOutput actionOutput;
+    private ActionSetVlanId actionSetVlanId;
+    private ActionSetVlanPriority actionSetVlanPriority;
+    private ActionStripVlan actionStripVlan;
+    private ActionSetEthernetAddr actionSetEthernetSrcAddr;
+    private ActionSetEthernetAddr actionSetEthernetDstAddr;
+    private ActionSetIPv4Addr actionSetIPv4SrcAddr;
+    private ActionSetIPv4Addr actionSetIPv4DstAddr;
+    private ActionSetIpToS actionSetIpToS;
+    private ActionSetTcpUdpPort actionSetTcpUdpSrcPort;
+    private ActionSetTcpUdpPort actionSetTcpUdpDstPort;
+    private ActionEnqueue actionEnqueue;
+
+    /**
+     * Default constructor.
+     */
+    public FlowEntryAction() {
+	actionType = ActionValues.ACTION_VENDOR;	// XXX: Initial value
+    }
+
+    /**
+     * Get the action type.
+     *
+     * @return the action type.
+     */
+    @JsonProperty("actionType")
+    public ActionValues actionType() { return actionType; }
+
+    /**
+     * Get the output action.
+     *
+     * @return the output action.
+     */
+    @JsonProperty("actionOutput")
+    public ActionOutput actionOutput() { return actionOutput; }
+
+    /**
+     * Set the output action on a port.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionOutput")
+    public void setActionOutput(ActionOutput action) {
+	actionOutput = action;
+	actionType = ActionValues.ACTION_OUTPUT;
+    }
+
+    /**
+     * Set the output action on a port.
+     *
+     * @param port the output port to set.
+     */
+    public void setActionOutput(Port port) {
+	actionOutput = new ActionOutput(port);
+	actionType = ActionValues.ACTION_OUTPUT;
+    }
+
+    /**
+     * Set the output action to controller.
+     *
+     * @param maxLen the maximum length (in bytes) to send to controller.
+     */
+    public void setActionOutputToController(short maxLen) {
+	Port port = new Port(Port.PortValues.PORT_CONTROLLER);
+	actionOutput = new ActionOutput(port, maxLen);
+	actionType = ActionValues.ACTION_OUTPUT;
+    }
+
+    /**
+     * Get the action to set the VLAN ID.
+     *
+     * @return the action to set the VLAN ID.
+     */
+    @JsonProperty("actionSetVlanId")
+    public ActionSetVlanId actionSetVlanId() { return actionSetVlanId; }
+
+    /**
+     * Set the action to set the VLAN ID.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetVlanId")
+    public void setActionSetVlanId(ActionSetVlanId action) {
+	actionSetVlanId = action;
+	actionType = ActionValues.ACTION_SET_VLAN_VID;
+    }
+
+    /**
+     * Set the action to set the VLAN ID.
+     *
+     * @param vlanId the VLAN ID to set.
+     */
+    public void setActionSetVlanId(short vlanId) {
+	actionSetVlanId = new ActionSetVlanId(vlanId);
+	actionType = ActionValues.ACTION_SET_VLAN_VID;
+    }
+
+    /**
+     * Get the action to set the VLAN priority.
+     *
+     * @return the action to set the VLAN priority.
+     */
+    @JsonProperty("actionSetVlanPriority")
+    public ActionSetVlanPriority actionSetVlanPriority() {
+	return actionSetVlanPriority;
+    }
+
+    /**
+     * Set the action to set the VLAN priority.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetVlanPriority")
+    public void setActionSetVlanPriority(ActionSetVlanPriority action) {
+	actionSetVlanPriority = action;
+	actionType = ActionValues.ACTION_SET_VLAN_PCP;
+    }
+
+    /**
+     * Set the action to set the VLAN priority.
+     *
+     * @param vlanPriority the VLAN priority to set.
+     */
+    public void setActionSetVlanPriority(byte vlanPriority) {
+	actionSetVlanPriority = new ActionSetVlanPriority(vlanPriority);
+	actionType = ActionValues.ACTION_SET_VLAN_PCP;
+    }
+
+    /**
+     * Get the action to strip the VLAN header.
+     *
+     * @return the action to strip the VLAN header.
+     */
+    @JsonProperty("actionStripVlan")
+    public ActionStripVlan actionStripVlan() {
+	return actionStripVlan;
+    }
+
+    /**
+     * Set the action to strip the VLAN header.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionStripVlan")
+    public void setActionStripVlan(ActionStripVlan action) {
+	actionStripVlan = action;
+	actionType = ActionValues.ACTION_STRIP_VLAN;
+    }
+
+    /**
+     * Set the action to strip the VLAN header.
+     *
+     * @param stripVlan if true, strip the VLAN header.
+     */
+    public void setActionStripVlan(boolean stripVlan) {
+	actionStripVlan = new ActionStripVlan(stripVlan);
+	actionType = ActionValues.ACTION_STRIP_VLAN;
+    }
+
+    /**
+     * Get the action to set the Ethernet source address.
+     *
+     * @return the action to set the Ethernet source address.
+     */
+    @JsonProperty("actionSetEthernetSrcAddr")
+    public ActionSetEthernetAddr actionSetEthernetSrcAddr() {
+	return actionSetEthernetSrcAddr;
+    }
+
+    /**
+     * Set the action to set the Ethernet source address.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetEthernetSrcAddr")
+    public void setActionSetEthernetSrcAddr(ActionSetEthernetAddr action) {
+	actionSetEthernetSrcAddr = action;
+	actionType = ActionValues.ACTION_SET_DL_SRC;
+    }
+
+    /**
+     * Set the action to set the Ethernet source address.
+     *
+     * @param addr the MAC address to set as the Ethernet source address.
+     */
+    public void setActionSetEthernetSrcAddr(MACAddress addr) {
+	actionSetEthernetSrcAddr = new ActionSetEthernetAddr(addr);
+	actionType = ActionValues.ACTION_SET_DL_SRC;
+    }
+
+    /**
+     * Get the action to set the Ethernet destination address.
+     *
+     * @return the action to set the Ethernet destination address.
+     */
+    @JsonProperty("actionSetEthernetDstAddr")
+    public ActionSetEthernetAddr actionSetEthernetDstAddr() {
+	return actionSetEthernetDstAddr;
+    }
+
+    /**
+     * Set the action to set the Ethernet destination address.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetEthernetDstAddr")
+    public void setActionSetEthernetDstAddr(ActionSetEthernetAddr action) {
+	actionSetEthernetDstAddr = action;
+	actionType = ActionValues.ACTION_SET_DL_DST;
+    }
+
+    /**
+     * Set the action to set the Ethernet destination address.
+     *
+     * @param addr the MAC address to set as the Ethernet destination address.
+     */
+    public void setActionSetEthernetDstAddr(MACAddress addr) {
+	actionSetEthernetDstAddr = new ActionSetEthernetAddr(addr);
+	actionType = ActionValues.ACTION_SET_DL_DST;
+    }
+
+    /**
+     * Get the action to set the IPv4 source address.
+     *
+     * @return the action to set the IPv4 source address.
+     */
+    @JsonProperty("actionSetIPv4SrcAddr")
+    public ActionSetIPv4Addr actionSetIPv4SrcAddr() {
+	return actionSetIPv4SrcAddr;
+    }
+
+    /**
+     * Set the action to set the IPv4 source address.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetIPv4SrcAddr")
+    public void setActionSetIPv4SrcAddr(ActionSetIPv4Addr action) {
+	actionSetIPv4SrcAddr = action;
+	actionType = ActionValues.ACTION_SET_NW_SRC;
+    }
+
+    /**
+     * Set the action to set the IPv4 source address.
+     *
+     * @param addr the IPv4 address to set as the IPv4 source address.
+     */
+    public void setActionSetIPv4SrcAddr(IPv4 addr) {
+	actionSetIPv4SrcAddr = new ActionSetIPv4Addr(addr);
+	actionType = ActionValues.ACTION_SET_NW_SRC;
+    }
+
+    /**
+     * Get the action to set the IPv4 destination address.
+     *
+     * @return the action to set the IPv4 destination address.
+     */
+    @JsonProperty("actionSetIPv4DstAddr")
+    public ActionSetIPv4Addr actionSetIPv4DstAddr() {
+	return actionSetIPv4DstAddr;
+    }
+
+    /**
+     * Set the action to set the IPv4 destination address.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetIPv4DstAddr")
+    public void setActionSetIPv4DstAddr(ActionSetIPv4Addr action) {
+	actionSetIPv4DstAddr = action;
+	actionType = ActionValues.ACTION_SET_NW_DST;
+    }
+
+    /**
+     * Set the action to set the IPv4 destination address.
+     *
+     * @param addr the IPv4 address to set as the IPv4 destination address.
+     */
+    public void setActionSetIPv4DstAddr(IPv4 addr) {
+	actionSetIPv4DstAddr = new ActionSetIPv4Addr(addr);
+	actionType = ActionValues.ACTION_SET_NW_DST;
+    }
+
+    /**
+     * Get the action to set the IP ToS (DSCP field, 6 bits).
+     *
+     * @return the action to set the IP ToS (DSCP field, 6 bits).
+     */
+    @JsonProperty("actionSetIpToS")
+    public ActionSetIpToS actionSetIpToS() {
+	return actionSetIpToS;
+    }
+
+    /**
+     * Set the action to set the IP ToS (DSCP field, 6 bits).
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetIpToS")
+    public void setActionSetIpToS(ActionSetIpToS action) {
+	actionSetIpToS = action;
+	actionType = ActionValues.ACTION_SET_NW_TOS;
+    }
+
+    /**
+     * Set the action to set the IP ToS (DSCP field, 6 bits).
+     *
+     * @param ipToS the IP ToS (DSCP field, 6 bits) to set.
+     */
+    public void setActionSetIpToS(byte ipToS) {
+	actionSetIpToS = new ActionSetIpToS(ipToS);
+	actionType = ActionValues.ACTION_SET_NW_TOS;
+    }
+
+    /**
+     * Get the action to set the TCP/UDP source port.
+     *
+     * @return the action to set the TCP/UDP source port.
+     */
+    @JsonProperty("actionSetTcpUdpSrcPort")
+    public ActionSetTcpUdpPort actionSetTcpUdpSrcPort() {
+	return actionSetTcpUdpSrcPort;
+    }
+
+    /**
+     * Set the action to set the TCP/UDP source port.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetTcpUdpSrcPort")
+    public void setActionSetTcpUdpSrcPort(ActionSetTcpUdpPort action) {
+	actionSetTcpUdpSrcPort = action;
+	actionType = ActionValues.ACTION_SET_TP_SRC;
+    }
+
+    /**
+     * Set the action to set the TCP/UDP source port.
+     *
+     * @param port the TCP/UDP port to set as the TCP/UDP source port.
+     */
+    public void setActionSetTcpUdpSrcPort(short port) {
+	actionSetTcpUdpSrcPort = new ActionSetTcpUdpPort(port);
+	actionType = ActionValues.ACTION_SET_TP_SRC;
+    }
+
+    /**
+     * Get the action to set the TCP/UDP destination port.
+     *
+     * @return the action to set the TCP/UDP destination port.
+     */
+    @JsonProperty("actionSetTcpUdpDstPort")
+    public ActionSetTcpUdpPort actionSetTcpUdpDstPort() {
+	return actionSetTcpUdpDstPort;
+    }
+
+    /**
+     * Set the action to set the TCP/UDP destination port.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionSetTcpUdpDstPort")
+    public void setActionSetTcpUdpDstPort(ActionSetTcpUdpPort action) {
+	actionSetTcpUdpDstPort = action;
+	actionType = ActionValues.ACTION_SET_TP_DST;
+    }
+
+    /**
+     * Set the action to set the TCP/UDP destination port.
+     *
+     * @param port the TCP/UDP port to set as the TCP/UDP destination port.
+     */
+    public void setActionSetTcpUdpDstPort(short port) {
+	actionSetTcpUdpDstPort = new ActionSetTcpUdpPort(port);
+	actionType = ActionValues.ACTION_SET_TP_DST;
+    }
+
+    /**
+     * Get the action to output to queue on a port.
+     *
+     * @return the action to output to queue on a port.
+     */
+    @JsonProperty("actionEnqueue")
+    public ActionEnqueue actionEnqueue() { return actionEnqueue; }
+
+    /**
+     * Set the action to output to queue on a port.
+     *
+     * @param action the action to set.
+     */
+    @JsonProperty("actionEnqueue")
+    public void setActionEnqueue(ActionEnqueue action) {
+	actionEnqueue = action;
+	actionType = ActionValues.ACTION_ENQUEUE;
+    }
+
+    /**
+     * Set the action to output to queue on a port.
+     *
+     * @param port the port to set.
+     * @param int queueId the queue ID to set.
+     */
+    public void setActionEnqueue(Port port, int queueId) {
+	actionEnqueue = new ActionEnqueue(port, queueId);
+	actionType = ActionValues.ACTION_ENQUEUE;
+    }
+
+    /**
+     * Convert the set of actions to a string.
+     *
+     * The string has the following form:
+     *  [type=XXX action=XXX]
+     *
+     * @return the set of actions as a string.
+     */
+    @Override
+    public String toString() {
+	String ret = "[";
+	ret += "type=" + actionType;
+	switch (actionType) {
+	case ACTION_OUTPUT:
+	    ret += " action=" + actionOutput.toString();
+	    break;
+	case ACTION_SET_VLAN_VID:
+	    ret += " action=" + actionSetVlanId.toString();
+	    break;
+	case ACTION_SET_VLAN_PCP:
+	    ret += " action=" + actionSetVlanPriority.toString();
+	    break;
+	case ACTION_STRIP_VLAN:
+	    ret += " action=" + actionStripVlan.toString();
+	    break;
+	case ACTION_SET_DL_SRC:
+	    ret += " action=" + actionSetEthernetSrcAddr.toString();
+	    break;
+	case ACTION_SET_DL_DST:
+	    ret += " action=" + actionSetEthernetDstAddr.toString();
+	    break;
+	case ACTION_SET_NW_SRC:
+	    ret += " action=" + actionSetIPv4SrcAddr.toString();
+	    break;
+	case ACTION_SET_NW_DST:
+	    ret += " action=" + actionSetIPv4DstAddr.toString();
+	    break;
+	case ACTION_SET_NW_TOS:
+	    ret += " action=" + actionSetIpToS.toString();
+	    break;
+	case ACTION_SET_TP_SRC:
+	    ret += " action=" + actionSetTcpUdpSrcPort.toString();
+	    break;
+	case ACTION_SET_TP_DST:
+	    ret += " action=" + actionSetTcpUdpDstPort.toString();
+	    break;
+	case ACTION_ENQUEUE:
+	    ret += " action=" + actionEnqueue.toString();
+	    break;
+	}
+	ret += "]";
+
+	return ret;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntryActions.java b/src/main/java/net/floodlightcontroller/util/FlowEntryActions.java
deleted file mode 100644
index 4d17de8..0000000
--- a/src/main/java/net/floodlightcontroller/util/FlowEntryActions.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.floodlightcontroller.util;
-
-import org.codehaus.jackson.annotate.JsonProperty;
-
-/**
- * The class representing the Flow Entry set of actions.
- *
- * The Flow Entry set of actions need to be applied to each packet.
- *
- * NOTE: This is just an empty placeholder (for now). The implied action is
- * forwarding on a single port.
- */
-public class FlowEntryActions {
-
-    /**
-     * Default constructor.
-     */
-    public FlowEntryActions() {
-    }
-
-    /**
-     * Convert the set of actions to a string.
-     *
-     * @return the set of actions as a string.
-     */
-    @Override
-    public String toString() {
-	String ret = "";
-	// TODO: Implement it!
-	return ret;
-    }
-}
diff --git a/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java b/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java
index 9bd3bea..64527c5 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntryMatch.java
@@ -10,18 +10,76 @@
  *
  * The Flow Entry matching filter that is used to specify
  * the network data that would be forwarded on the data path from
- * the source to the destination. Examples: MAC address (of the
- * sender), IP prefix that includes the destination's IP address, etc.
- *
- * NOTE: The FlowEntryMatch specification below is incomplete: we need
- * more matching fields, we need to indicate which fields need to be
- * matched, etc.
+ * the source to the destination. Examples: source or destination MAC address,
+ * IP prefix that includes the destination's IP address, etc.
  */
 public class FlowEntryMatch {
-    private MACAddress srcMac;		// Matching source MAC address
-    private MACAddress dstMac;		// Matching destination MAC address
-    private IPv4Net srcIPv4Net;		// Matching source IPv4 prefix
-    private IPv4Net dstIPv4Net;		// Matching destination IPv4 prefix
+    /**
+     * A class for storing a value to match.
+     */
+    class Field<T> {
+	/**
+	 * Default constructor.
+	 */
+	public Field() {
+	    this.enabled = false;
+	}
+
+	/**
+	 * Constructor for a given value to match.
+	 */
+	public Field(T value) {
+	    this.value = value;
+	    this.enabled = true;
+	}
+
+	/**
+	 * Get the value.
+	 *
+	 * @return the value.
+	 */
+	public T value() { return this.value; }
+
+	/**
+	 * Enable the matching for a given value.
+	 *
+	 * @param value the value to set.
+	 */
+	public void enableMatch(T value) {
+	    this.value = value;
+	    this.enabled = true;
+	}
+
+	/**
+	 * Disable the matching.
+	 */
+	public void disableMatch() {
+	    this.enabled = false;
+	}
+
+	/**
+	 * Test whether matching is enabled.
+	 *
+	 * @return true if matching is enabled, otherwise false.
+	 */
+	public boolean enabled() { return this.enabled; }
+
+	private T value;		// The value to match
+	private boolean enabled;	// Set to true, if matching is enabled
+    }
+
+    private Field<Port> inPort;		// Matching input switch port
+    private Field<MACAddress> srcMac;	// Matching source MAC address
+    private Field<MACAddress> dstMac;	// Matching destination MAC address
+    private Field<Short> vlanId;	// Matching VLAN ID
+    private Field<Byte> vlanPriority;	// Matching VLAN priority
+    private Field<Short> ethernetFrameType; // Matching Ethernet frame type
+    private Field<Byte> ipToS;		// Matching IP ToS (DSCP field, 6 bits)
+    private Field<Byte> ipProto;	// Matching IP protocol
+    private Field<IPv4Net> srcIPv4Net;	// Matching source IPv4 prefix
+    private Field<IPv4Net> dstIPv4Net;	// Matching destination IPv4 prefix
+    private Field<Short> srcTcpUdpPort;	// Matching source TCP/UDP port
+    private Field<Short> dstTcpUdpPort;	// Matching destination TCP/UDP port
 
     /**
      * Default constructor.
@@ -30,21 +88,85 @@
     }
 
     /**
+     * Get the matching input switch port.
+     *
+     * @return the matching input switch port.
+     */
+    @JsonProperty("inPort")
+    public Port inPort() {
+	if (inPort != null)
+	    return inPort.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on input switch port.
+     *
+     * @param inPort the input switch port value to enable for matching.
+     */
+    @JsonProperty("inPort")
+    public void enableInPort(Port inPort) {
+	this.inPort = new Field<Port>(inPort);
+    }
+
+    /**
+     * Disable the matching on input switch port.
+     */
+    public void disableInPort() {
+	this.inPort = null;
+    }
+
+    /**
+     * Test if matching on input switch port is enabled.
+     *
+     * @return true if matching on input switch port is enabled.
+     */
+    @JsonProperty("matchInPort")
+    public boolean matchInPort() {
+	if (inPort != null)
+	    return inPort.enabled();
+	return false;
+    }
+
+    /**
      * Get the matching source MAC address.
      *
      * @return the matching source MAC address.
      */
     @JsonProperty("srcMac")
-    public MACAddress srcMac() { return srcMac; }
+    public MACAddress srcMac() {
+	if (srcMac != null)
+	    return srcMac.value();
+	return null;
+    }
 
     /**
-     * Set the matching source MAC address.
+     * Enable the matching on source MAC address.
      *
-     * @param srcMac the matching source MAC address to set.
+     * @param srcMac the source MAC address value to enable for matching.
      */
     @JsonProperty("srcMac")
-    public void setSrcMac(MACAddress srcMac) {
-	this.srcMac = srcMac;
+    public void enableSrcMac(MACAddress srcMac) {
+	this.srcMac = new Field<MACAddress>(srcMac);
+    }
+
+    /**
+     * Disable the matching on source MAC address.
+     */
+    public void disableSrcMac() {
+	this.srcMac = null;
+    }
+
+    /**
+     * Test if matching on source MAC address is enabled.
+     *
+     * @return true if matching on source MAC address is enabled.
+     */
+    @JsonProperty("matchSrcMac")
+    public boolean matchSrcMac() {
+	if (srcMac != null)
+	    return srcMac.enabled();
+	return false;
     }
 
     /**
@@ -53,16 +175,245 @@
      * @return the matching destination MAC address.
      */
     @JsonProperty("dstMac")
-    public MACAddress dstMac() { return dstMac; }
+    public MACAddress dstMac() {
+	if (dstMac != null)
+	    return dstMac.value();
+	return null;
+    }
 
     /**
-     * Set the matching destination MAC address.
+     * Enable the matching on destination MAC address.
      *
-     * @param dstMac the matching destination MAC address to set.
+     * @param dstMac the destination MAC address value to enable for matching.
      */
     @JsonProperty("dstMac")
-    public void setDstMac(MACAddress dstMac) {
-	this.dstMac = dstMac;
+    public void enableDstMac(MACAddress dstMac) {
+	this.dstMac = new Field<MACAddress>(dstMac);
+    }
+
+    /**
+     * Disable the matching on destination MAC address.
+     */
+    public void disableDstMac() {
+	this.dstMac = null;
+    }
+
+    /**
+     * Test if matching on destination MAC address is enabled.
+     *
+     * @return true if matching on destination MAC address is enabled.
+     */
+    @JsonProperty("matchDstMac")
+    public boolean matchDstMac() {
+	if (dstMac != null)
+	    return dstMac.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching VLAN ID.
+     *
+     * @return the matching VLAN ID.
+     */
+    @JsonProperty("vlanId")
+    public Short vlanId() {
+	if (vlanId != null)
+	    return vlanId.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on VLAN ID.
+     *
+     * @param vlanId the VLAN ID value to enable for matching.
+     */
+    @JsonProperty("vlanId")
+    public void enableVlanId(Short vlanId) {
+	this.vlanId = new Field<Short>(vlanId);
+    }
+
+    /**
+     * Disable the matching on VLAN ID.
+     */
+    public void disableVlanId() {
+	this.vlanId = null;
+    }
+
+    /**
+     * Test if matching on VLAN ID is enabled.
+     *
+     * @return true if matching on VLAN ID is enabled.
+     */
+    @JsonProperty("matchVlanId")
+    public boolean matchVlanId() {
+	if (vlanId != null)
+	    return vlanId.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching VLAN priority.
+     *
+     * @return the matching VLAN priority.
+     */
+    @JsonProperty("vlanPriority")
+    public Byte vlanPriority() {
+	if (vlanPriority != null)
+	    return vlanPriority.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on VLAN priority.
+     *
+     * @param vlanPriority the VLAN priority value to enable for matching.
+     */
+    @JsonProperty("vlanPriority")
+    public void enableVlanPriority(Byte vlanPriority) {
+	this.vlanPriority = new Field<Byte>(vlanPriority);
+    }
+
+    /**
+     * Disable the matching on VLAN priority.
+     */
+    public void disableVlanPriority() {
+	this.vlanPriority = null;
+    }
+
+    /**
+     * Test if matching on VLAN priority is enabled.
+     *
+     * @return true if matching on VLAN priority is enabled.
+     */
+    @JsonProperty("matchVlanPriority")
+    public boolean matchVlanPriority() {
+	if (vlanPriority != null)
+	    return vlanPriority.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching Ethernet frame type.
+     *
+     * @return the matching Ethernet frame type.
+     */
+    @JsonProperty("ethernetFrameType")
+    public Short ethernetFrameType() {
+	if (ethernetFrameType != null)
+	    return ethernetFrameType.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on Ethernet frame type.
+     *
+     * @param ethernetFrameType the Ethernet frame type value to enable for
+     * matching.
+     */
+    @JsonProperty("ethernetFrameType")
+    public void enableEthernetFrameType(Short ethernetFrameType) {
+	this.ethernetFrameType = new Field<Short>(ethernetFrameType);
+    }
+
+    /**
+     * Disable the matching on Ethernet frame type.
+     */
+    public void disableEthernetFrameType() {
+	this.ethernetFrameType = null;
+    }
+
+    /**
+     * Test if matching on Ethernet frame type is enabled.
+     *
+     * @return true if matching on Ethernet frame type is enabled.
+     */
+    @JsonProperty("matchEthernetFrameType")
+    public boolean matchEthernetFrameType() {
+	if (ethernetFrameType != null)
+	    return ethernetFrameType.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching IP ToS (DSCP field, 6 bits)
+     *
+     * @return the matching IP ToS.
+     */
+    @JsonProperty("ipToS")
+    public Byte ipToS() {
+	if (ipToS != null)
+	    return ipToS.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on IP ToS (DSCP field, 6 bits).
+     *
+     * @param ipToS the IP ToS value to enable for matching.
+     */
+    @JsonProperty("ipToS")
+    public void enableIpToS(Byte ipToS) {
+	this.ipToS = new Field<Byte>(ipToS);
+    }
+
+    /**
+     * Disable the matching on IP ToS (DSCP field, 6 bits).
+     */
+    public void disableIpToS() {
+	this.ipToS = null;
+    }
+
+    /**
+     * Test if matching on IP ToS (DSCP field, 6 bits) is enabled.
+     *
+     * @return true if matching on IP ToS is enabled.
+     */
+    @JsonProperty("matchIpToS")
+    public boolean matchIpToS() {
+	if (ipToS != null)
+	    return ipToS.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching IP protocol.
+     *
+     * @return the matching IP protocol.
+     */
+    @JsonProperty("ipProto")
+    public Byte ipProto() {
+	if (ipProto != null)
+	    return ipProto.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on IP protocol.
+     *
+     * @param ipProto the IP protocol value to enable for matching.
+     */
+    @JsonProperty("ipProto")
+    public void enableIpProto(Byte ipProto) {
+	this.ipProto = new Field<Byte>(ipProto);
+    }
+
+    /**
+     * Disable the matching on IP protocol.
+     */
+    public void disableIpProto() {
+	this.ipProto = null;
+    }
+
+    /**
+     * Test if matching on IP protocol is enabled.
+     *
+     * @return true if matching on IP protocol is enabled.
+     */
+    @JsonProperty("matchIpProto")
+    public boolean matchIpProto() {
+	if (ipProto != null)
+	    return ipProto.enabled();
+	return false;
     }
 
     /**
@@ -71,16 +422,39 @@
      * @return the matching source IPv4 prefix.
      */
     @JsonProperty("srcIPv4Net")
-    public IPv4Net srcIPv4Net() { return srcIPv4Net; }
+    public IPv4Net srcIPv4Net() {
+	if (srcIPv4Net != null)
+	    return srcIPv4Net.value();
+	return null;
+    }
 
     /**
-     * Set the matching source IPv4 prefix.
+     * Enable the matching on source IPv4 prefix.
      *
-     * @param srcIPv4Net the matching source IPv4 prefix to set.
+     * @param srcIPv4Net the source IPv4 prefix value to enable for matching.
      */
     @JsonProperty("srcIPv4Net")
-    public void setSrcIPv4Net(IPv4Net srcIPv4Net) {
-	this.srcIPv4Net = srcIPv4Net;
+    public void enableSrcIPv4Net(IPv4Net srcIPv4Net) {
+	this.srcIPv4Net = new Field<IPv4Net>(srcIPv4Net);
+    }
+
+    /**
+     * Disable the matching on source IPv4 prefix.
+     */
+    public void disableSrcIPv4Net() {
+	this.srcIPv4Net = null;
+    }
+
+    /**
+     * Test if matching on source IPv4 prefix is enabled.
+     *
+     * @return true if matching on source IPv4 prefix is enabled.
+     */
+    @JsonProperty("matchSrcIPv4Net")
+    public boolean matchSrcIPv4Net() {
+	if (srcIPv4Net != null)
+	    return srcIPv4Net.enabled();
+	return false;
     }
 
     /**
@@ -89,16 +463,123 @@
      * @return the matching destination IPv4 prefix.
      */
     @JsonProperty("dstIPv4Net")
-    public IPv4Net dstIPv4Net() { return dstIPv4Net; }
+    public IPv4Net dstIPv4Net() {
+	if (dstIPv4Net != null)
+	    return dstIPv4Net.value();
+	return null;
+    }
 
     /**
-     * Set the matching destination IPv4 prefix.
+     * Enable the matching on destination IPv4 prefix.
      *
-     * @param srcIPv4Net the matching destination IPv4 prefix to set.
+     * @param dstIPv4Net the destination IPv4 prefix value to enable for
+     * matching.
      */
     @JsonProperty("dstIPv4Net")
-    public void setDstIPv4Net(IPv4Net dstIPv4Net) {
-	this.dstIPv4Net = dstIPv4Net;
+    public void enableDstIPv4Net(IPv4Net dstIPv4Net) {
+	this.dstIPv4Net = new Field<IPv4Net>(dstIPv4Net);
+    }
+
+    /**
+     * Disable the matching on destination IPv4 prefix.
+     */
+    public void disableDstIPv4Net() {
+	this.dstIPv4Net = null;
+    }
+
+    /**
+     * Test if matching on destination IPv4 prefix is enabled.
+     *
+     * @return true if matching on destination IPv4 prefix is enabled.
+     */
+    @JsonProperty("matchDstIPv4Net")
+    public boolean matchDstIPv4Net() {
+	if (dstIPv4Net != null)
+	    return dstIPv4Net.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching source TCP/UDP port.
+     *
+     * @return the matching source TCP/UDP port.
+     */
+    @JsonProperty("srcTcpUdpPort")
+    public Short srcTcpUdpPort() {
+	if (srcTcpUdpPort != null)
+	    return srcTcpUdpPort.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on source TCP/UDP port.
+     *
+     * @param srcTcpUdpPort the source TCP/UDP port to enable for matching.
+     */
+    @JsonProperty("srcTcpUdpPort")
+    public void enableSrcTcpUdpPort(Short srcTcpUdpPort) {
+	this.srcTcpUdpPort = new Field<Short>(srcTcpUdpPort);
+    }
+
+    /**
+     * Disable the matching on source TCP/UDP port.
+     */
+    public void disableSrcTcpUdpPort() {
+	this.srcTcpUdpPort = null;
+    }
+
+    /**
+     * Test if matching on source TCP/UDP port is enabled.
+     *
+     * @return true if matching on source TCP/UDP port is enabled.
+     */
+    @JsonProperty("matchSrcTcpUdpPort")
+    public boolean matchSrcTcpUdpPort() {
+	if (srcTcpUdpPort != null)
+	    return srcTcpUdpPort.enabled();
+	return false;
+    }
+
+    /**
+     * Get the matching destination TCP/UDP port.
+     *
+     * @return the matching destination TCP/UDP port.
+     */
+    @JsonProperty("dstTcpUdpPort")
+    public Short dstTcpUdpPort() {
+	if (dstTcpUdpPort != null)
+	    return dstTcpUdpPort.value();
+	return null;
+    }
+
+    /**
+     * Enable the matching on destination TCP/UDP port.
+     *
+     * @param dstTcpUdpPort the destination TCP/UDP port to enable for
+     * matching.
+     */
+    @JsonProperty("dstTcpUdpPort")
+    public void enableDstTcpUdpPort(Short dstTcpUdpPort) {
+	this.dstTcpUdpPort = new Field<Short>(dstTcpUdpPort);
+    }
+
+    /**
+     * Disable the matching on destination TCP/UDP port.
+     */
+    public void disableDstTcpUdpPort() {
+	this.dstTcpUdpPort = null;
+    }
+
+    /**
+     * Test if matching on destination TCP/UDP port is enabled.
+     *
+     * @return true if matching on destination TCP/UDP port is enabled.
+     */
+    @JsonProperty("matchDstTcpUdpPort")
+    public boolean matchDstTcpUdpPort() {
+	if (dstTcpUdpPort != null)
+	    return dstTcpUdpPort.enabled();
+	return false;
     }
 
     /**
@@ -111,11 +592,87 @@
      */
     @Override
     public String toString() {
-	String ret = "[srcMac=" + this.srcMac.toString();
-	ret += " dstMac=" + this.dstMac.toString();
-	ret += " srcIPv4Net=" + this.srcIPv4Net.toString();
-	ret += " dstIPv4Net=" + this.dstIPv4Net.toString();
+	String ret = "[";
+	boolean addSpace = false;
+
+	//
+	// Conditionally add only those matching fields that are enabled
+	//
+	if (matchInPort()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "inPort=" + this.inPort().toString();
+	}
+	if (matchSrcMac()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "srcMac=" + this.srcMac().toString();
+	}
+	if (matchDstMac()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "dstMac=" + this.dstMac().toString();
+	}
+	if (matchVlanId()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "vlanId=" + this.vlanId().toString();
+	}
+	if (matchVlanPriority()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "vlanPriority=" + this.vlanPriority().toString();
+	}
+	if (matchEthernetFrameType()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "ethernetFrameType=" + this.ethernetFrameType().toString();
+	}
+	if (matchIpToS()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "ipToS=" + this.ipToS().toString();
+	}
+	if (matchIpProto()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "ipProto=" + this.ipProto().toString();
+	}
+	if (matchSrcIPv4Net()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "srcIPv4Net=" + this.srcIPv4Net().toString();
+	}
+	if (matchDstIPv4Net()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "dstIPv4Net=" + this.dstIPv4Net().toString();
+	}
+	if (matchSrcTcpUdpPort()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "srcTcpUdpPort=" + this.srcTcpUdpPort().toString();
+	}
+	if (matchDstTcpUdpPort()) {
+	    if (addSpace)
+		ret += " ";
+	    addSpace = true;
+	    ret += "dstTcpUdpPort=" + this.dstTcpUdpPort().toString();
+	}
+
 	ret += "]";
+
 	return ret;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/util/MACAddress.java b/src/main/java/net/floodlightcontroller/util/MACAddress.java
index 4ba9dad..743dc5b 100644
--- a/src/main/java/net/floodlightcontroller/util/MACAddress.java
+++ b/src/main/java/net/floodlightcontroller/util/MACAddress.java
@@ -2,11 +2,20 @@
 
 import java.util.Arrays;
 
+import net.floodlightcontroller.util.serializers.MACAddressDeserializer;
+import net.floodlightcontroller.util.serializers.MACAddressSerializer;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonDeserialize;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
 /**
  * The class representing MAC address.
  *
  * @author Sho Shimizu (sho.shimizu@gmail.com)
  */
+@JsonDeserialize(using=MACAddressDeserializer.class)
+@JsonSerialize(using=MACAddressSerializer.class)
 public class MACAddress {
     public static final int MAC_ADDRESS_LENGTH = 6;
     private byte[] address = new byte[MAC_ADDRESS_LENGTH];
diff --git a/src/main/java/net/floodlightcontroller/util/Port.java b/src/main/java/net/floodlightcontroller/util/Port.java
index 19bbf8f..41f0d55 100644
--- a/src/main/java/net/floodlightcontroller/util/Port.java
+++ b/src/main/java/net/floodlightcontroller/util/Port.java
@@ -5,7 +5,69 @@
 /**
  * The class representing a network port of a switch.
  */
+
 public class Port {
+    /**
+     * Special port values.
+     *
+     * Those values are taken as-is from the OpenFlow-v1.0.0 specification
+     * (pp 18-19).
+     */
+    public enum PortValues {
+	/* Maximum number of physical switch ports. */
+	PORT_MAX		((short)0xff00),
+
+	/* Fake output "ports". */
+
+	/* Send the packet out the input port. This
+	   virtual port must be explicitly used
+	   in order to send back out of the input
+	   port. */
+	PORT_IN_PORT		((short)0xfff8),
+
+	/* Perform actions in flow table.
+	   NB: This can only be the destination
+	   port for packet-out messages. */
+	PORT_TABLE		((short)0xfff9),
+
+	/* Process with normal L2/L3 switching. */
+	PORT_NORMAL		((short)0xfffa),
+
+	/* All physical ports except input port and
+	   those disabled by STP. */
+	PORT_FLOOD		((short)0xfffb),
+
+	/* All physical ports except input port. */
+	PORT_ALL		((short)0xfffc),
+
+	/* Send to controller. */
+	PORT_CONTROLLER		((short)0xfffd),
+
+	/* Local openflow "port". */
+	PORT_LOCAL		((short)0xfffe),
+
+	/* Not associated with a physical port. */
+	PORT_NONE		((short)0xffff);
+
+	private final short value;	// The value
+
+	/**
+	 * Constructor for a given value.
+	 *
+	 * @param value the value to use for the initialization.
+	 */
+	private PortValues(short value) {
+	    this.value = value;
+	}
+
+	/**
+	 * Get the value as a short integer.
+	 *
+	 * @return the value as a short integer.
+	 */
+	private short value() { return this.value; }
+    }
+
     private short value;
 
     /**
@@ -25,7 +87,7 @@
     }
 
     /**
-     * Constructor from a long value.
+     * Constructor from a short integer value.
      *
      * @param value the value to use.
      */
@@ -34,6 +96,15 @@
     }
 
     /**
+     * Constructor from a PortValues enum value.
+     *
+     * @param value the value to use.
+     */
+    public Port(PortValues value) {
+	this.value = value.value();
+    }
+
+    /**
      * Get the value of the port.
      *
      * @return the value of the port.
diff --git a/src/main/java/net/floodlightcontroller/util/serializers/IPv4Deserializer.java b/src/main/java/net/floodlightcontroller/util/serializers/IPv4Deserializer.java
index 7ce7d5c..275f9f0 100644
--- a/src/main/java/net/floodlightcontroller/util/serializers/IPv4Deserializer.java
+++ b/src/main/java/net/floodlightcontroller/util/serializers/IPv4Deserializer.java
@@ -16,7 +16,7 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Deserialize an IPv4 from a string.
+ * Deserialize an IPv4 address from a string.
  */
 public class IPv4Deserializer extends JsonDeserializer<IPv4> {
 
diff --git a/src/main/java/net/floodlightcontroller/util/serializers/IPv4NetDeserializer.java b/src/main/java/net/floodlightcontroller/util/serializers/IPv4NetDeserializer.java
index e35fc80..3c36870 100644
--- a/src/main/java/net/floodlightcontroller/util/serializers/IPv4NetDeserializer.java
+++ b/src/main/java/net/floodlightcontroller/util/serializers/IPv4NetDeserializer.java
@@ -16,7 +16,7 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Deserialize an IPv4Net from a string.
+ * Deserialize an IPv4Net address from a string.
  */
 public class IPv4NetDeserializer extends JsonDeserializer<IPv4Net> {
 
diff --git a/src/main/java/net/floodlightcontroller/util/serializers/IPv6Deserializer.java b/src/main/java/net/floodlightcontroller/util/serializers/IPv6Deserializer.java
index 6713f93..818de30 100644
--- a/src/main/java/net/floodlightcontroller/util/serializers/IPv6Deserializer.java
+++ b/src/main/java/net/floodlightcontroller/util/serializers/IPv6Deserializer.java
@@ -16,7 +16,7 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Deserialize an IPv6 from a string.
+ * Deserialize an IPv6 address from a string.
  */
 public class IPv6Deserializer extends JsonDeserializer<IPv6> {
 
diff --git a/src/main/java/net/floodlightcontroller/util/serializers/IPv6NetDeserializer.java b/src/main/java/net/floodlightcontroller/util/serializers/IPv6NetDeserializer.java
index 596ee50..375dc26 100644
--- a/src/main/java/net/floodlightcontroller/util/serializers/IPv6NetDeserializer.java
+++ b/src/main/java/net/floodlightcontroller/util/serializers/IPv6NetDeserializer.java
@@ -16,7 +16,7 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * Deserialize an IPv6Net from a string.
+ * Deserialize an IPv6Net address from a string.
  */
 public class IPv6NetDeserializer extends JsonDeserializer<IPv6Net> {
 
diff --git a/src/main/java/net/floodlightcontroller/util/serializers/MACAddressDeserializer.java b/src/main/java/net/floodlightcontroller/util/serializers/MACAddressDeserializer.java
new file mode 100644
index 0000000..35b384d
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/serializers/MACAddressDeserializer.java
@@ -0,0 +1,43 @@
+package net.floodlightcontroller.util.serializers;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.JsonToken;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.ObjectCodec;
+import org.codehaus.jackson.map.JsonDeserializer;
+import org.codehaus.jackson.map.DeserializationContext;
+
+import net.floodlightcontroller.util.MACAddress;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Deserialize a MAC address from a string.
+ */
+public class MACAddressDeserializer extends JsonDeserializer<MACAddress> {
+
+    protected static Logger log = LoggerFactory.getLogger(MACAddressDeserializer.class);
+
+    @Override
+    public MACAddress deserialize(JsonParser jp,
+				  DeserializationContext ctxt)
+	throws IOException, JsonProcessingException {
+
+	MACAddress mac = null;
+
+	jp.nextToken();		// Move to JsonToken.START_OBJECT
+	while (jp.nextToken() != JsonToken.END_OBJECT) {
+	    String fieldname = jp.getCurrentName();
+	    if ("value".equals(fieldname)) {
+		String value = jp.getText();
+		log.debug("Fieldname: " + fieldname + " Value: " + value);
+		mac = MACAddress.valueOf(value);
+	    }
+	}
+	return mac;
+    }
+}
diff --git a/src/main/java/net/floodlightcontroller/util/serializers/MACAddressSerializer.java b/src/main/java/net/floodlightcontroller/util/serializers/MACAddressSerializer.java
new file mode 100644
index 0000000..dec2596
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/serializers/MACAddressSerializer.java
@@ -0,0 +1,25 @@
+package net.floodlightcontroller.util.serializers;
+
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonProcessingException;
+import org.codehaus.jackson.map.JsonSerializer;
+import org.codehaus.jackson.map.SerializerProvider;
+
+import net.floodlightcontroller.util.MACAddress;
+
+/**
+ * Serialize a MAC address as a string.
+ */
+public class MACAddressSerializer extends JsonSerializer<MACAddress> {
+
+    @Override
+    public void serialize(MACAddress mac, JsonGenerator jGen,
+			  SerializerProvider serializer)
+	throws IOException, JsonProcessingException {
+	jGen.writeStartObject();
+	jGen.writeStringField("value", mac.toString());
+	jGen.writeEndObject();
+    }
+}
diff --git a/src/main/java/org/openflow/protocol/OFMatch.java b/src/main/java/org/openflow/protocol/OFMatch.java
index 0336d7d..397263d 100644
--- a/src/main/java/org/openflow/protocol/OFMatch.java
+++ b/src/main/java/org/openflow/protocol/OFMatch.java
@@ -911,7 +911,7 @@
      *            one of STR_NW_DST or STR_NW_SRC
      * @throws IllegalArgumentException
      */
-    private void setFromCIDR(String cidr, String which)
+    public void setFromCIDR(String cidr, String which)
             throws IllegalArgumentException {
         String values[] = cidr.split("/");
         String[] ip_str = values[0].split("\\.");
diff --git a/web/add_flow.py b/web/add_flow.py
index 18846b7..d8788ee 100755
--- a/web/add_flow.py
+++ b/web/add_flow.py
@@ -1,6 +1,7 @@
 #! /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
@@ -84,7 +85,36 @@
     exit(1)
 
 if __name__ == "__main__":
-  usage_msg = "Usage: %s <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port>" % (sys.argv[0])
+  usage_msg = "Usage: %s <flow-id> <installer-id> <src-dpid> <src-port> <dest-dpid> <dest-port> [Match Conditions] [Actions]\n" % (sys.argv[0])
+  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 + "    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 + "    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 + "    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;
 
@@ -98,10 +128,16 @@
     log_error(usage_msg)
     exit(1)
 
-  # Do the work
+  # Extract the mandatory arguments
   my_flow_id = sys.argv[1]
-  my_installer_id = sys.argv[2];	# 'ONOS-Path-Computation-Python'
-  data_path = shortest_path(sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])
+  my_installer_id = sys.argv[2]
+  my_src_dpid = sys.argv[3]
+  my_src_port = sys.argv[4]
+  my_dst_dpid = sys.argv[5]
+  my_dst_port = sys.argv[6]
+
+  # Compute the shortest path
+  data_path = shortest_path(my_src_dpid, my_src_port, my_dst_dpid, my_dst_port)
 
   debug("Data Path: %s" % data_path)
 
@@ -113,6 +149,214 @@
   flow_path = {}
   flow_path['flowId'] = flow_id
   flow_path['installerId'] = installer_id
+
+  #
+  # Extract the "match" and "action" arguments
+  #
+  idx = 7
+  match = {}
+  matchInPortEnabled = True		# NOTE: Enabled by default
+  actions = []
+  actionOutputEnabled = True		# NOTE: Enabled by default
+  while idx < len(sys.argv):
+    action = {}
+    arg1 = sys.argv[idx]
+    idx = idx + 1
+    # Extract the second argument
+    if idx >= len(sys.argv):
+      error_arg = "ERROR: Missing or invalid '" + arg1 + "' argument"
+      log_error(error_arg)
+      log_error(usage_msg)
+      exit(1)
+    arg2 = sys.argv[idx]
+    idx = idx + 1
+
+    if arg1 == "matchInPort":
+      # Just mark whether inPort matching is enabled
+      matchInPortEnabled = arg2 in ['True', 'true']
+      # inPort = {}
+      # inPort['value'] = int(arg2)
+      # 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)
+      # match['matchVlanId'] = True
+    elif arg1 == "matchVlanPriority":
+      match['vlanPriority'] = int(arg2)
+      # match['matchVlanPriority'] = True
+    elif arg1 == "matchEthernetFrameType":
+      match['ethernetFrameType'] = int(arg2)
+      # match['matchEthernetFrameType'] = True
+    elif arg1 == "matchIpToS":
+      match['ipToS'] = int(arg2)
+      # match['matchIpToS'] = True
+    elif arg1 == "matchIpProto":
+      match['ipProto'] = int(arg2)
+      # 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)
+      # match['matchSrcTcpUdpPort'] = True
+    elif arg1 == "matchDstTcpUdpPort":
+      match['dstTcpUdpPort'] = int(arg2)
+      # 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)
+      #   actionOutput['port'] = outPort
+      #   actionOutput['maxLen'] = int(arg3)
+      #   action['actionOutput'] = actionOutput
+      #   # action['actionType'] = 'ACTION_OUTPUT'
+      #   actions.append(action)
+      #
+    elif arg1 == "actionSetVlanId":
+      vlanId = {}
+      vlanId['vlanId'] = int(arg2)
+      action['actionSetVlanId'] = vlanId
+      # action['actionType'] = 'ACTION_SET_VLAN_VID'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetVlanPriority":
+      vlanPriority = {}
+      vlanPriority['vlanPriority'] = int(arg2)
+      action['actionSetVlanPriority'] = vlanPriority
+      # action['actionType'] = 'ACTION_SET_VLAN_PCP'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetIpToS":
+      ipToS = {}
+      ipToS['ipToS'] = int(arg2)
+      action['actionSetIpToS'] = ipToS
+      # action['actionType'] = 'ACTION_SET_NW_TOS'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetTcpUdpSrcPort":
+      tcpUdpSrcPort = {}
+      tcpUdpSrcPort['port'] = int(arg2)
+      action['actionSetTcpUdpSrcPort'] = tcpUdpSrcPort
+      # action['actionType'] = 'ACTION_SET_TP_SRC'
+      actions.append(copy.deepcopy(action))
+    elif arg1 == "actionSetTcpUdpDstPort":
+      tcpUdpDstPort = {}
+      tcpUdpDstPort['port'] = int(arg2)
+      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)
+      #   enqueuePort = {}
+      #   enqueuePort['value'] = int(arg3)
+      #   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)
+
+
+  #
+  # Add the match conditions to each flow entry
+  #
+  if (len(match) > 0) or matchInPortEnabled:
+    idx = 0
+    while idx < len(data_path['flowEntries']):
+      if matchInPortEnabled:
+	inPort = data_path['flowEntries'][idx]['inPort']
+	match['inPort'] = copy.deepcopy(inPort)
+	# match['matchInPort'] = True
+      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(data_path['flowEntries']):
+      if idx > 0:
+	actions = []	# Reset the actions for all but first entry
+      action = {}
+      outPort = 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))
+
+      data_path['flowEntries'][idx]['flowEntryActions'] = copy.deepcopy(actions)
+      idx = idx + 1
+
+
   flow_path['dataPath'] = data_path
 
   flow_path_json = json.dumps(flow_path)
diff --git a/web/get_flow.py b/web/get_flow.py
index b20e134..eaf50d3 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -34,22 +34,124 @@
 # {"flowId":{"value":"0x5"},"installerId":{"value":"FOOBAR"},"dataPath":{"srcPort":{"dpid":{"value":"00:00:00:00:00:00:00:01"},"port":{"value":0}},"dstPort":{"dpid":{"value":"00:00:00:00:00:00:00:02"},"port":{"value":0}},"flowEntries":[{"flowEntryId":"0x1389","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:01"},"inPort":{"value":0},"outPort":{"value":1},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null},{"flowEntryId":"0x138a","flowEntryMatch":null,"flowEntryActions":null,"dpid":{"value":"00:00:00:00:00:00:00:02"},"inPort":{"value":9},"outPort":{"value":0},"flowEntryUserState":"FE_USER_DELETE","flowEntrySwitchState":"FE_SWITCH_NOT_UPDATED","flowEntryErrorState":null}]}}
 
 def print_flow_path(parsedResult):
-  flowId = parsedResult['flowId']['value'];
-  installerId = parsedResult['installerId']['value'];
-  srcSwitch = parsedResult['dataPath']['srcPort']['dpid']['value'];
-  srcPort = parsedResult['dataPath']['srcPort']['port']['value'];
-  dstSwitch = parsedResult['dataPath']['dstPort']['dpid']['value'];
-  dstPort = parsedResult['dataPath']['dstPort']['port']['value'];
+  flowId = parsedResult['flowId']['value']
+  installerId = parsedResult['installerId']['value']
+  srcSwitch = parsedResult['dataPath']['srcPort']['dpid']['value']
+  srcPort = parsedResult['dataPath']['srcPort']['port']['value']
+  dstSwitch = parsedResult['dataPath']['dstPort']['dpid']['value']
+  dstPort = parsedResult['dataPath']['dstPort']['port']['value']
 
   print "FlowPath: (flowId = %s installerId = %s src = %s/%s dst = %s/%s)" % (flowId, installerId, srcSwitch, srcPort, dstSwitch, dstPort)
 
   for f in parsedResult['dataPath']['flowEntries']:
-    inPort = f['inPort']['value'];
-    outPort = f['outPort']['value'];
     dpid = f['dpid']['value']
     userState = f['flowEntryUserState']
     switchState = f['flowEntrySwitchState']
-    print "  FlowEntry: (%s, %s, %s, %s, %s)" % (inPort, dpid, outPort, userState, switchState)
+    match = f['flowEntryMatch'];
+    actions = f['flowEntryActions']
+    print "  FlowEntry: (%s, %s, %s)" % (dpid, userState, switchState)
+
+    #
+    # Print the match 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" % 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
+
+    #
+    # Print the actions
+    #
+    if actions == None:
+      print "   Actions: %s" % (actions)
+    else:
+      for a in actions:
+	actionType = a['actionType']
+	if actionType == "ACTION_OUTPUT":
+	  port = a['actionOutput']['port']
+	  maxLen = a['actionOutput']['maxLen']
+	  print "    actionType: %s port: %s maxLen: %s" % (actionType, port, maxLen)
+	if actionType == "ACTION_SET_VLAN_VID":
+	  vlanId = a['actionSetVlanId']['vlanId']
+	  print "    actionType: %s vlanId: %s" % (actionType, vlanId)
+	if actionType == "ACTION_SET_VLAN_PCP":
+	  vlanPriority = a['actionSetVlanPriority']['vlanPriority']
+	  print "    actionType: %s vlanPriority: %s" % (actionType, vlanPriority)
+	if actionType == "ACTION_STRIP_VLAN":
+	  stripVlan = a['actionStripVlan']['stripVlan']
+	  print "    actionType: %s stripVlan: %s" % (actionType, stripVlan)
+	if actionType == "ACTION_SET_DL_SRC":
+	  setEthernetSrcAddr = a['actionSetEthernetSrcAddr']['addr']['value']
+	  print "    actionType: %s setEthernetSrcAddr: %s" % (actionType, setEthernetSrcAddr)
+	if actionType == "ACTION_SET_DL_DST":
+	  setEthernetDstAddr = a['actionSetEthernetDstAddr']['addr']['value']
+	  print "    actionType: %s setEthernetDstAddr: %s" % (actionType, setEthernetDstAddr)
+	if actionType == "ACTION_SET_NW_SRC":
+	  setIPv4SrcAddr = a['actionSetIPv4SrcAddr']['addr']['value']
+	  print "    actionType: %s setIPv4SrcAddr: %s" % (actionType, setIPv4SrcAddr)
+	if actionType == "ACTION_SET_NW_DST":
+	  setIPv4DstAddr = a['actionSetIPv4DstAddr']['addr']['value']
+	  print "    actionType: %s setIPv4DstAddr: %s" % (actionType, setIPv4DstAddr)
+	if actionType == "ACTION_SET_NW_TOS":
+	  setIpToS = a['actionSetIpToS']['ipToS']
+	  print "    actionType: %s setIpToS: %s" % (actionType, setIpToS)
+	if actionType == "ACTION_SET_TP_SRC":
+	  setTcpUdpSrcPort = a['actionSetTcpUdpSrcPort']['port']
+	  print "    actionType: %s setTcpUdpSrcPort: %s" % (actionType, setTcpUdpSrcPort)
+	if actionType == "ACTION_SET_TP_DST":
+	  setTcpUdpDstPort = a['actionSetTcpUdpDstPort']['port']
+	  print "    actionType: %s setTcpUdpDstPort: %s" % (actionType, setTcpUdpDstPort)
+	if actionType == "ACTION_ENQUEUE":
+	  port = a['actionEnqueue']['port']['value']
+	  queueId = a['actionEnqueue']['queueId']
+	  print "    actionType: %s port: %s queueId: %s" % (actionType, port, queueId)
 
 def get_flow_path(flow_id):
   try: