Work toward Issue #215 and Issue #216:
 * Implemented the top-level API to support matching conditions and
   actions for flows.
 * Added Json serializer/deserializer for MACAddress.
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
index a5f759c..8cf1982 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowManager.java
@@ -367,7 +367,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.
 	    //
 
@@ -647,7 +647,7 @@
 	    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..304bb5c
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/FlowEntryAction.java
@@ -0,0 +1,820 @@
+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
+
+	/**
+	 * 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;
+	}
+
+	/**
+	 * 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
+
+	/**
+	 * Constructor for a given VLAN ID.
+	 *
+	 * @param vlanId the VLAN ID to set.
+	 */
+	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
+
+	/**
+	 * Constructor for a given VLAN priority.
+	 *
+	 * @param vlanPriority the VLAN priority to set.
+	 */
+	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
+
+	/**
+	 * Constructor for a given boolean flag.
+	 *
+	 * @param stripVlan if true, strip the VLAN header.
+	 */
+	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
+
+	/**
+	 * Constructor for a given MAC address.
+	 *
+	 * @param addr the MAC address to set.
+	 */
+	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
+
+	/**
+	 * Constructor for a given IPv4 address.
+	 *
+	 * @param addr the IPv4 address to set.
+	 */
+	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)
+
+	/**
+	 * Constructor for a given IP ToS (DSCP field, 6 bits).
+	 *
+	 * @param ipToS the IP ToS (DSCP field, 6 bits) to set.
+	 */
+	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
+
+	/**
+	 * Constructor for a given TCP/UDP port.
+	 *
+	 * @param port the TCP/UDP port to set.
+	 */
+	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
+
+	/**
+	 * 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 port the output port to set.
+     */
+    @JsonProperty("actionOutput")
+    public void setActionOutput(Port port) {
+	actionOutput = new ActionOutput(port, (short)0);
+	actionType = ActionValues.ACTION_OUTPUT;
+    }
+
+    /**
+     * Set the output action to controller.
+     *
+     * @param maxLen the maximum length (in bytes) to send to controller.
+     */
+    @JsonProperty("actionOutputToController")
+    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 vlanId the VLAN ID to set.
+     */
+    @JsonProperty("actionSetVlanId")
+    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 vlanPriority the VLAN priority to set.
+     */
+    @JsonProperty("actionSetVlanPriority")
+    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 stripVlan if true, strip the VLAN header.
+     */
+    @JsonProperty("actionStripVlan")
+    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 addr the MAC address to set as the Ethernet source address.
+     */
+    @JsonProperty("actionSetEthernetSrcAddr")
+    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 addr the MAC address to set as the Ethernet destination address.
+     */
+    @JsonProperty("actionSetEthernetDstAddr")
+    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 addr the IPv4 address to set as the IPv4 source address.
+     */
+    @JsonProperty("actionSetIPv4SrcAddr")
+    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 addr the IPv4 address to set as the IPv4 destination address.
+     */
+    @JsonProperty("actionSetIPv4DstAddr")
+    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 ipToS the IP ToS (DSCP field, 6 bits) to set.
+     */
+    @JsonProperty("actionSetIpToS")
+    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 port the TCP/UDP port to set as the TCP/UDP source port.
+     */
+    @JsonProperty("actionSetTcpUdpSrcPort")
+    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 port the TCP/UDP port to set as the TCP/UDP destination port.
+     */
+    @JsonProperty("actionSetTcpUdpDstPort")
+    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 port the port to set.
+     * @param int queueId the queue ID to set.
+     */
+    @JsonProperty("actionEnqueue")
+    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/web/get_flow.py b/web/get_flow.py
index b20e134..dd6a8b6 100755
--- a/web/get_flow.py
+++ b/web/get_flow.py
@@ -34,23 +34,115 @@
 # {"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'];
+    inPort = f['inPort']['value']
+    outPort = f['outPort']['value']
     dpid = f['dpid']['value']
     userState = f['flowEntryUserState']
     switchState = f['flowEntrySwitchState']
+    match = f['flowEntryMatch'];
+    actions = f['flowEntryActions']
     print "  FlowEntry: (%s, %s, %s, %s, %s)" % (inPort, dpid, outPort, userState, switchState)
 
+    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
+
+    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:
     command = "curl -s \"http://%s:%s/wm/flow/get/%s/json\"" % (ControllerIP, ControllerPort, flow_id)