diff --git a/build.xml b/build.xml
index bed6c6081d4964a5d764284d52b4dcfe6ad22b7a..2a0094bbd873f6b032265a003773d390f18d8f24 100644
--- a/build.xml
+++ b/build.xml
@@ -44,8 +44,8 @@
     <property name="floodlight-test-jar" location="${target}/floodlight-test.jar"/>
     <property name="thrift.dir" value="${basedir}/src/main/thrift"/>
     <property name="thrift.out.dir" value="lib/gen-java"/>
-    <property name="ant.build.javac.source" value="1.6"/>
-    <property name="ant.build.javac.target" value="1.6"/>
+    <property name="ant.build.javac.source" value="1.7"/>
+    <property name="ant.build.javac.target" value="1.7"/>
     <property name="findbugs.home" value="../build/findbugs-2.0.2"/>
     <property name="findbugs.results" value="findbugs-results" />
     <property name="lib" location="lib"/>
@@ -75,6 +75,11 @@
         <include name="findbugs-annotations-2.0.1.jar" />
         <include name="findbugs-jsr305-2.0.1.jar" />
         <include name="derby-10.9.1.0.jar"/>
+    	<include name="openflowj-0.3.5-SNAPSHOT.jar"/>
+    	<include name="openflowj-0.3.5-SNAPSHOT-javadoc.jar"/>
+    	<include name="hamcrest-core-1.3.jar"/>
+    	<include name="hamcrest-integration-1.3.jar"/>
+    	<include name="hamcrest-library-1.3.jar"/>
     </patternset>
 
     <path id="classpath">
diff --git a/lib/openflowj-0.3.5-SNAPSHOT-javadoc.jar b/lib/openflowj-0.3.5-SNAPSHOT-javadoc.jar
new file mode 100644
index 0000000000000000000000000000000000000000..49c3f4551b6588514f1b18581e274c688fbf5bce
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT-javadoc.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT-sources.jar b/lib/openflowj-0.3.5-SNAPSHOT-sources.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5786ced23c2b240d20195b3acef6e18a3e676db5
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT-sources.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT-tests.jar b/lib/openflowj-0.3.5-SNAPSHOT-tests.jar
new file mode 100644
index 0000000000000000000000000000000000000000..67646a8c35818bb017599121b16d7aff19718d9a
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT-tests.jar differ
diff --git a/lib/openflowj-0.3.5-SNAPSHOT.jar b/lib/openflowj-0.3.5-SNAPSHOT.jar
new file mode 100644
index 0000000000000000000000000000000000000000..dcb33c10e467f75f74ea96062893d7608d6ce71c
Binary files /dev/null and b/lib/openflowj-0.3.5-SNAPSHOT.jar differ
diff --git a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
index c04eb5eef1dad04b7918e52c5df4673fdee29505..d8564f5703ec17b30cf53642e3225dd7f549e9ca 100644
--- a/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/ControllerSwitchesResource.java
@@ -101,7 +101,7 @@ public class ControllerSwitchesResource extends ServerResource {
         }
 
         public String getDpid() {
-            return sw.getStringId();
+            return sw.getId().toString();
         }
 
         public String getHarole() {
diff --git a/src/main/java/net/floodlightcontroller/core/web/CounterResource.java b/src/main/java/net/floodlightcontroller/core/web/CounterResource.java
index 14fa1b1e347cc9c2c8652e673c5448483477aae8..c08e5b3aa4026a580d9e99abc162e92aeb9d7589 100644
--- a/src/main/java/net/floodlightcontroller/core/web/CounterResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/CounterResource.java
@@ -31,7 +31,7 @@ import org.restlet.resource.Get;
 public class CounterResource extends CounterResourceBase {
     @Get("json")
     public Map<String, Object> retrieve() {
-        String counterTitle = 
+        /*TODO @Ryan String counterTitle = 
             (String) getRequestAttributes().get("counterTitle");
         Map<String, Object> model = new HashMap<String,Object>();
         long dc;
@@ -61,6 +61,6 @@ public class CounterResource extends CounterResourceBase {
                 model.put(counterTitle, v.getDouble());
             }   
         }
-        return model;
+        return model;*/ return null;
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
index 98c2a73753f0cb3fe84597eac0a64b29d61999a3..66ba78641b569aacb6a4dedae26de4c2bf2551a2 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterCategoriesResource.java
@@ -61,7 +61,7 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase {
                                                      String switchID,
                                                      String counterName,
                                                      String layer) {
-        String fullCounterName = "";
+        /*TODO @Ryan String fullCounterName = "";
         NetworkLayer nl = NetworkLayer.L3;
 
         try {
@@ -78,6 +78,6 @@ public class SwitchCounterCategoriesResource extends CounterResourceBase {
         List<String> categories = this.counterStore.getAllCategories(fullCounterName, nl);
         if (categories != null) {
             model.put(fullCounterName + "." + layer, categories);
-        }
+        }*/
     }
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
index 61667daee959a7788753bc065613a3bf59cae462..8f33337d8f696028bba9c2b3e930556c8b0abb97 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchCounterResource.java
@@ -34,7 +34,7 @@ import net.floodlightcontroller.core.internal.IOFSwitchService;
 public class SwitchCounterResource extends CounterResourceBase {
     @Get("json")
     public Map<String, Object> retrieve() {
-        IOFSwitchService switchService =
+        /*TODO @Ryan IOFSwitchService switchService =
                 (IOFSwitchService)getContext().getAttributes().
                     get(IOFSwitchService.class.getCanonicalName());
         HashMap<String,Object> model = new HashMap<String,Object>();
@@ -52,12 +52,12 @@ public class SwitchCounterResource extends CounterResourceBase {
         } else {
             getOneSwitchCounterJson(model, switchID, counterName);
         }
-        return model;
+        return model;*/ return null;
     }
 
     protected void getOneSwitchCounterJson(Map<String, Object> model,
                                            String switchID, String counterName) {
-        String fullCounterName = "";
+        /*TODO @Ryan String fullCounterName = "";
 
         try {
             counterName = URLDecoder.decode(counterName, "UTF-8");
@@ -73,7 +73,7 @@ public class SwitchCounterResource extends CounterResourceBase {
             sample.put(counter.getCounterDate().toString(),
                        counter.getCounterValue().getLong());
             model.put(switchID, sample);
-        }
+        } */
     }
 
 }
diff --git a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
index 63ccc7178552ed994abdce4785f06b94e4c50790..45d9bc12fefcf6c10dd683cb1e4f6bdc066bd9a0 100644
--- a/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
+++ b/src/main/java/net/floodlightcontroller/core/web/SwitchRoleResource.java
@@ -47,7 +47,7 @@ public class SwitchRoleResource extends ServerResource {
         if (switchId.equalsIgnoreCase("all")) {
             HashMap<String,RoleInfo> model = new HashMap<String,RoleInfo>();
             for (IOFSwitch sw: switchService.getAllSwitchMap().values()) {
-                switchId = sw.getStringId();
+                switchId = sw.getId().toString();
                 //TODO @Ryan not sure what the changeDescription string should be here.
                 roleInfo = new RoleInfo(HARole.ofOFRole(sw.getControllerRole()), "", null);
                 model.put(switchId, roleInfo);
diff --git a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
index 0ad0c7b69aed40ee547fb380df0a0e6e2ed0b02a..578a15e60d15cc41294155e052082b107b9562b2 100644
--- a/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
+++ b/src/main/java/net/floodlightcontroller/flowcache/FlowReconcileManager.java
@@ -362,7 +362,7 @@ public class FlowReconcileManager implements IFloodlightModule, IFlowReconcileSe
      * @return
      */
     protected int getCurrentCapacity() {
-        int minFlows = MIN_FLOW_RECONCILE_PER_SECOND * FLOW_RECONCILE_DELAY_MILLISEC / 1000;
+        /*int minFlows = MIN_FLOW_RECONCILE_PER_SECOND * FLOW_RECONCILE_DELAY_MILLISEC / 1000;
         
         List<DebugCounterResource> contCtrRsrcList = debugCounterService.getModuleCounterValues(Controller.class.getName());
         for (DebugCounterResource dcr : contCtrRsrcList) {
@@ -398,11 +398,11 @@ public class FlowReconcileManager implements IFloodlightModule, IFlowReconcileSe
         if (logger.isTraceEnabled()) {
             logger.trace("Capacity is {}", capacity);
         }
-        return capacity;
+        return capacity; */ return 0;
     }
 
     protected int getPktInRate(DebugCounterResource newCnt, Date currentTime) {
-        if (newCnt == null ||
+        /*if (newCnt == null ||
             newCnt.getCounterDate() == null ||
             newCnt.getCounterValue() == null) {
             return 0;
@@ -450,7 +450,7 @@ public class FlowReconcileManager implements IFloodlightModule, IFlowReconcileSe
                 break;
         }
 
-        return (int)(diff/elapsedTimeInSecond);
+        return (int)(diff/elapsedTimeInSecond); */ return 0;
     }
 }
 
diff --git a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
index b70a646f90896caf75169b19fa3d358e2155f061..f14134c5f17b651c9294b031667fdb13f109b9fd 100644
--- a/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
+++ b/src/main/java/net/floodlightcontroller/loadbalancer/LoadBalancer.java
@@ -24,33 +24,16 @@ import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPacketIn;
 import org.projectfloodlight.openflow.protocol.OFPacketOut;
 import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwTos;
-import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.protocol.action.OFActionStripVlan;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetTpSrc;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetTpDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp; // PCP = Priority Code Point
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.IPv4Address;
 import org.projectfloodlight.openflow.types.IpProtocol;
@@ -60,8 +43,6 @@ import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.TransportPort;
 import org.projectfloodlight.openflow.types.U16;
 import org.projectfloodlight.openflow.types.U64;
-import org.projectfloodlight.openflow.types.VlanPcp;
-import org.projectfloodlight.openflow.types.VlanVid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -91,7 +72,9 @@ import net.floodlightcontroller.routing.Route;
 import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
 import net.floodlightcontroller.topology.ITopologyService;
 import net.floodlightcontroller.topology.NodePortTuple;
-import net.floodlightcontroller.util.MatchString;
+import net.floodlightcontroller.util.ActionUtils;
+import net.floodlightcontroller.util.FlowModUtils;
+import net.floodlightcontroller.util.MatchUtils;
 import net.floodlightcontroller.util.OFMessageDamper;
 
 /**
@@ -143,10 +126,8 @@ public class LoadBalancer implements IFloodlightModule,
             new Comparator<SwitchPort>() {
                 @Override
                 public int compare(SwitchPort d1, SwitchPort d2) {
-                    DatapathId d1ClusterId = 
-                            topologyService.getL2DomainId(d1.getSwitchDPID());
-                    DatapathId d2ClusterId = 
-                            topologyService.getL2DomainId(d2.getSwitchDPID());
+                    DatapathId d1ClusterId = topologyService.getL2DomainId(d1.getSwitchDPID());
+                    DatapathId d2ClusterId = topologyService.getL2DomainId(d2.getSwitchDPID());
                     return d1ClusterId.compareTo(d2ClusterId);
                 }
             };
@@ -308,8 +289,7 @@ public class LoadBalancer implements IFloodlightModule,
                         arpRequest.getSenderProtocolAddress()));
                 
         // push ARP reply out
-        pushPacket(arpReply, sw, OFBufferId.NO_BUFFER, OFPort.ZERO,
-                   pi.getInPort(), cntx, true); //TODO @Ryan is OFPort.ZERO == NONE (no port)?
+        pushPacket(arpReply, sw, OFBufferId.NO_BUFFER, OFPort.ZERO, pi.getInPort(), cntx, true);
         log.debug("proxy ARP reply pushed as {}", IPv4.fromIPv4Address(vips.get(vipId).address));
         
         return;
@@ -391,7 +371,7 @@ public class LoadBalancer implements IFloodlightModule,
         
         for (IDevice d : allDevices) {
             for (int j = 0; j < d.getIPv4Addresses().length; j++) {
-                    if (srcDevice == null && client.ipAddress == d.getIPv4Addresses()[j])
+                    if (srcDevice == null && client.ipAddress.equals(d.getIPv4Addresses()[j]))
                         srcDevice = d;
                     if (dstDevice == null && member.address == d.getIPv4Addresses()[j].getInt()) {
                         dstDevice = d;
@@ -422,8 +402,8 @@ public class LoadBalancer implements IFloodlightModule,
             DatapathId dstIsland = topologyService.getL2DomainId(dstSwDpid);
             if ((dstIsland != null) && dstIsland.equals(srcIsland)) {
                 on_same_island = true;
-                if ((sw.getId() == dstSwDpid) &&
-                        (pi.getInPort() == dstDap.getPort())) {
+                if ((sw.getId().equals(dstSwDpid)) &&
+                        (pi.getInPort().equals(dstDap.getPort()))) {
                     on_same_if = true;
                 }
                 break;
@@ -518,7 +498,7 @@ public class LoadBalancer implements IFloodlightModule,
      */
     public void pushStaticVipRoute(boolean inBound, Route route, IPClient client, LBMember member, DatapathId pinSwitch) {
         List<NodePortTuple> path = route.getPath();
-        if (path.size()>0) {
+        if (path.size() > 0) {
            for (int i = 0; i < path.size(); i+=2) {
                
                DatapathId sw = path.get(i).getNodeId();
@@ -529,21 +509,21 @@ public class LoadBalancer implements IFloodlightModule,
                
                OFFlowMod.Builder fmb = switchService.getSwitch(pinSwitch).getOFFactory().buildFlowModify();
 
-               fmb.setIdleTimeout((short) 0);   // infinite
-               fmb.setHardTimeout((short) 0);   // infinite
+               fmb.setIdleTimeout(FlowModUtils.INFINITE_TIMEOUT);
+               fmb.setHardTimeout(FlowModUtils.INFINITE_TIMEOUT);
                fmb.setBufferId(OFBufferId.NO_BUFFER);
-               fmb.setOutPort(OFPort.ANY); //TODO @Ryan is this the same as OFPort.NONE in the old openflowj?
+               fmb.setOutPort(OFPort.ZERO);
                fmb.setCookie(U64.of(0));  
                fmb.setPriority(Short.MAX_VALUE);
                
                if (inBound) {
                    entryName = "inbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort
                            +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw;
-                   matchString = "nw_src="+client.ipAddress.toString()+","
-                               + "nw_proto="+String.valueOf(client.nw_proto)+","
-                               + "tp_src="+client.srcPort.toString()+","
-                               + "dl_type="+LB_ETHER_TYPE+","
-                               + "in_port="+path.get(i).getPortId().toString();
+                   matchString = MatchUtils.STR_NW_SRC + "="+client.ipAddress.toString()+","
+                               + MatchUtils.STR_NW_PROTO + "="+String.valueOf(client.nw_proto)+","
+                               + MatchUtils.STR_TP_SRC + "="+client.srcPort.toString()+","
+                               + MatchUtils.STR_DL_TYPE + "="+LB_ETHER_TYPE+","
+                               + MatchUtils.STR_IN_PORT + "="+path.get(i).getPortId().toString();
 
                    if (sw == pinSwitch) {
                        actionString = "set-dst-ip="+IPv4.fromIPv4Address(member.address)+"," 
@@ -556,29 +536,29 @@ public class LoadBalancer implements IFloodlightModule,
                } else {
                    entryName = "outbound-vip-"+ member.vipId+"-client-"+client.ipAddress+"-port-"+client.targetPort
                            +"-srcswitch-"+path.get(0).getNodeId()+"-sw-"+sw;
-                   matchString = "nw_dst="+client.ipAddress.toString()+","
-                               + "nw_proto="+client.nw_proto.toString()+","
-                               + "tp_dst="+client.srcPort.toString()+","
-                               + "dl_type="+LB_ETHER_TYPE+","
-                               + "in_port="+path.get(i).getPortId().toString();
+                   matchString = MatchUtils.STR_NW_DST + "="+client.ipAddress.toString()+","
+                               + MatchUtils.STR_NW_PROTO + "="+client.nw_proto.toString()+","
+                               + MatchUtils.STR_TP_DST + "="+client.srcPort.toString()+","
+                               + MatchUtils.STR_DL_TYPE + "="+LB_ETHER_TYPE+","
+                               + MatchUtils.STR_IN_PORT + "="+path.get(i).getPortId().toString();
 
                    if (sw == pinSwitch) {
-                       actionString = "set-src-ip="+IPv4.fromIPv4Address(vips.get(member.vipId).address)+","
-                               + "set-src-mac="+vips.get(member.vipId).proxyMac.toString()+","
-                               + "output="+path.get(i+1).getPortId();
+                       actionString = ActionUtils.STR_NW_SRC_SET + "="+IPv4.fromIPv4Address(vips.get(member.vipId).address)+","
+                               + ActionUtils.STR_DL_SRC_SET + "="+vips.get(member.vipId).proxyMac.toString()+","
+                               + ActionUtils.STR_OUTPUT + "="+path.get(i+1).getPortId();
                    } else {
-                       actionString = "output="+path.get(i+1).getPortId();
+                       actionString = ActionUtils.STR_OUTPUT + "="+path.get(i+1).getPortId();
                    }
                    
                }
                
-               parseActionString(fmb.build(), actionString, log);
+               ActionUtils.fromString(fmb, actionString, log);
 
                fmb.setPriority(U16.t(LB_PRIORITY));
 
                Match match = null;
                try {
-                   match = MatchString.fromString(matchString, switchService.getSwitch(sw).getOFFactory().getVersion());
+                   match = MatchUtils.fromString(matchString, switchService.getSwitch(sw).getOFFactory().getVersion());
                } catch (IllegalArgumentException e) {
                    log.debug("ignoring flow entry {} on switch {} with illegal OFMatch() key: " + matchString, entryName, swString);
                }
@@ -646,7 +626,7 @@ public class LoadBalancer implements IFloodlightModule,
 
     @Override
     public LBPool createPool(LBPool pool) {
-        if (pool==null)
+        if (pool == null)
             pool = new LBPool();
         
         pools.put(pool.id, pool);
@@ -669,7 +649,7 @@ public class LoadBalancer implements IFloodlightModule,
     @Override
     public int removePool(String poolId) {
         LBPool pool;
-        if(pools!=null){
+        if (pools != null) {
             pool = pools.get(poolId);
             if (pool.vipId != null)
                 vips.get(pool.vipId).pools.remove(poolId);
@@ -698,7 +678,7 @@ public class LoadBalancer implements IFloodlightModule,
         
         if(pools.containsKey(poolId)) {
             ArrayList<String> memberIds = pools.get(poolId).members;
-            for (int i=0; i<memberIds.size(); i++)
+            for (int i = 0; i<memberIds.size(); i++)
                 result.add(members.get(memberIds.get(i)));
         }
         return result;
@@ -833,476 +813,4 @@ public class LoadBalancer implements IFloodlightModule,
         floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
         restApiService.addRestletRoutable(new LoadBalancerWebRoutable());
     }
-
-    // Utilities borrowed from StaticFlowEntries
-    
-    private static class SubActionStruct {
-        OFAction action;
-    }
-    
-    /**
-     * Parses OFFlowMod actions from strings.
-     * @param flowMod The OFFlowMod to set the actions for
-     * @param actionstr The string containing all the actions
-     * @param log A logger to log for errors.
-     */
-    public static void parseActionString(OFFlowMod flowMod, String actionstr, Logger log) {
-        List<OFAction> actions = new LinkedList<OFAction>();
-        OFVersion version = flowMod.getVersion();
-        if (actionstr != null) {
-            actionstr = actionstr.toLowerCase();
-            for (String subaction : actionstr.split(",")) {
-                String action = subaction.split("[=:]")[0];
-                SubActionStruct subaction_struct = null;
-                
-                if (action.equals("output")) {
-                    subaction_struct = decode_output(subaction, version, log);
-                }
-                else if (action.equals("enqueue")) {
-                    subaction_struct = decode_enqueue(subaction, version, log);
-                }
-                else if (action.equals("strip-vlan")) {
-                    subaction_struct = decode_strip_vlan(subaction, version, log);
-                }
-                else if (action.equals("set-vlan-id")) {
-                    subaction_struct = decode_set_vlan_id(subaction, version, log);
-                }
-                else if (action.equals("set-vlan-priority")) {
-                    subaction_struct = decode_set_vlan_priority(subaction, version, log);
-                }
-                else if (action.equals("set-src-mac")) {
-                    subaction_struct = decode_set_src_mac(subaction, version, log);
-                }
-                else if (action.equals("set-dst-mac")) {
-                    subaction_struct = decode_set_dst_mac(subaction, version, log);
-                }
-                else if (action.equals("set-tos-bits")) {
-                    subaction_struct = decode_set_tos_bits(subaction, version, log);
-                }
-                else if (action.equals("set-src-ip")) {
-                    subaction_struct = decode_set_src_ip(subaction, version, log);
-                }
-                else if (action.equals("set-dst-ip")) {
-                    subaction_struct = decode_set_dst_ip(subaction, version, log);
-                }
-                else if (action.equals("set-src-port")) {
-                    subaction_struct = decode_set_src_port(subaction, version, log);
-                }
-                else if (action.equals("set-dst-port")) {
-                    subaction_struct = decode_set_dst_port(subaction, version, log);
-                }
-                else {
-                    log.error("Unexpected action '{}', '{}'", action, subaction);
-                }
-                
-                if (subaction_struct != null) {
-                    actions.add(subaction_struct.action);
-                }
-            }
-        }
-        log.debug("action {}", actions);
-        
-        flowMod = flowMod.createBuilder().setActions(actions).build();
-    } 
-    
-    private static SubActionStruct decode_output(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction);
-        if (n.matches()) {
-            OFActionOutput.Builder ab = OFFactories.getFactory(version).actions().buildOutput();
-            OFPort port = OFPort.ANY; //TODO @Ryan is ANY == NONE?
-            if (n.group(1) != null) {
-                try {
-                    port = OFPort.of(get_short(n.group(1)));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else if (n.group(2) != null)
-                port = OFPort.ALL;
-            else if (n.group(3) != null)
-                port = OFPort.CONTROLLER;
-            else if (n.group(4) != null)
-                port = OFPort.LOCAL;
-            else if (n.group(5) != null)
-                port = OFPort.IN_PORT;
-            else if (n.group(6) != null)
-                port = OFPort.NORMAL;
-            else if (n.group(7) != null)
-                port = OFPort.FLOOD;
-            ab.setPort(port);
-            log.debug("action {}", ab.build());
-            
-            sa = new SubActionStruct();
-            sa.action = ab.build();
-        }
-        else {
-            log.error("Invalid subaction: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_enqueue(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction);
-        if (n.matches()) {
-            OFPort portnum = OFPort.of(0);
-            if (n.group(1) != null) {
-                try {
-                    portnum = OFPort.of(get_short(n.group(1)));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port-num in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-
-            int queueid = 0;
-            if (n.group(2) != null) {
-                try {
-                    queueid = get_int(n.group(2));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid queue-id in: '{}' (error ignored)", subaction);
-                    return null;
-               }
-            }
-            
-            OFActionEnqueue.Builder aeb = OFFactories.getFactory(version).actions().buildEnqueue();
-            aeb.setPort(portnum);
-            aeb.setQueueId(queueid);
-            log.debug("action {}", aeb.build());
-            
-            sa = new SubActionStruct();
-            sa.action = aeb.build();
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_strip_vlan(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("strip-vlan").matcher(subaction);
-        
-        if (n.matches()) {
-            OFActionStripVlan asvl = OFFactories.getFactory(version).actions().stripVlan();
-            log.debug("action {}", asvl);
-            
-            sa = new SubActionStruct();
-            sa.action = asvl;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_id(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
-        
-        if (n.matches()) {            
-            if (n.group(1) != null) {
-                try {
-                    short vlanid = get_short(n.group(1));
-                    OFActionSetVlanVid.Builder avvid = OFFactories.getFactory(version).actions().buildSetVlanVid();
-                    avvid.setVlanVid(VlanVid.ofVlan(vlanid));
-                    log.debug("  action {}", avvid.build());
-
-                    sa = new SubActionStruct();
-                    sa.action = avvid.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }          
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_priority(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); 
-        
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    byte prior = get_byte(n.group(1));
-                    OFActionSetVlanPcp.Builder avpcp = OFFactories.getFactory(version).actions().buildSetVlanPcp();
-                    avpcp.setVlanPcp(VlanPcp.of(prior));
-                    log.debug("  action {}", avpcp.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = avpcp.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN priority in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_mac(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); 
-
-        if (n.matches()) {
-            byte[] macaddr = get_mac_addr(n, subaction, log);
-            if (macaddr != null) {
-                OFActionSetDlSrc.Builder asdls = OFFactories.getFactory(version).actions().buildSetDlSrc();
-                asdls.setDlAddr(MacAddress.of(macaddr));
-                log.debug("action {}", asdls.build());
-
-                sa = new SubActionStruct();
-                sa.action = asdls.build();
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_mac(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
-        
-        if (n.matches()) {
-            byte[] macaddr = get_mac_addr(n, subaction, log);
-            if (macaddr != null) {
-                OFActionSetDlDst.Builder asdld = OFFactories.getFactory(version).actions().buildSetDlDst();
-                asdld.setDlAddr(MacAddress.of(macaddr));
-                log.debug("  action {}", asdld.build());
-                
-                sa = new SubActionStruct();
-                sa.action = asdld.build();
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_tos_bits(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    byte tosbits = get_byte(n.group(1));
-                    OFActionSetNwTos.Builder snwtos = OFFactories.getFactory(version).actions().buildSetNwTos();
-                    snwtos.setNwTos(tosbits);
-                    log.debug("  action {}", snwtos.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = snwtos.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_ip(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            int ipaddr = get_ip_addr(n, subaction, log);
-            OFActionSetNwSrc.Builder snws = OFFactories.getFactory(version).actions().buildSetNwSrc();
-            snws.setNwAddr(IPv4Address.of(ipaddr));
-            log.debug("  action {}", snws.build());
-
-            sa = new SubActionStruct();
-            sa.action = snws.build();
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_ip(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            int ipaddr = get_ip_addr(n, subaction, log);
-            OFActionSetNwDst.Builder snwd = OFFactories.getFactory(version).actions().buildSetNwDst();
-            snwd.setNwAddr(IPv4Address.of(ipaddr));
-            log.debug("action {}", snwd.build());
- 
-            sa = new SubActionStruct();
-            sa.action = snwd.build();
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_src_port(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    TransportPort portnum = TransportPort.of(get_short(n.group(1)));
-                    OFActionSetTpSrc.Builder stps = OFFactories.getFactory(version).actions().buildSetTpSrc();
-                    stps.setTpPort(portnum);
-                    log.debug("action {}", stps.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = stps.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_port(String subaction, OFVersion version, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    TransportPort portnum = TransportPort.of(get_short(n.group(1)));
-                    OFActionSetTpDst.Builder stpd = OFFactories.getFactory(version).actions().buildSetTpDst();
-                    stpd.setTpPort(portnum);
-                    log.debug("action {}", stpd);
-                    
-                    sa = new SubActionStruct();
-                    sa.action = stpd.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) {
-        byte[] macaddr = new byte[6];
-        
-        for (int i=0; i<6; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    macaddr[i] = get_byte("0x" + n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-mac in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else { 
-                log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction);
-                return null;
-            }
-        }
-        
-        return macaddr;
-    }
-    
-    private static int get_ip_addr(Matcher n, String subaction, Logger log) {
-        int ipaddr = 0;
-
-        for (int i=0; i<4; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    ipaddr = ipaddr<<8;
-                    ipaddr = ipaddr | get_int(n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-ip in: '{}' (error ignored)", subaction);
-                    return 0;
-                }
-            }
-            else {
-                log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction);
-                return 0;
-            }
-        }
-        
-        return ipaddr;
-    }
-    
-    // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static int get_int(String str) {
-        return Integer.decode(str);
-    }
-   
-    // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static short get_short(String str) {
-        return (short)(int)Integer.decode(str);
-    }
-   
-    // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static byte get_byte(String str) {
-        return Integer.decode(str).byteValue();
-    }
-
-    
 }
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java
index b0dfdf5d51391356cacf1c79360200ee1389c3be..72d52bd49d05bd64f29d382519ad0f867cad698f 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntries.java
@@ -18,15 +18,12 @@ package net.floodlightcontroller.staticflowentry;
 
 import java.io.IOException;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Iterator;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import net.floodlightcontroller.core.annotations.LogMessageCategory;
-import net.floodlightcontroller.core.annotations.LogMessageDoc;
 import net.floodlightcontroller.core.util.AppCookie;
+import net.floodlightcontroller.util.ActionUtils;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,32 +33,12 @@ import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonToken;
 import com.fasterxml.jackson.databind.MappingJsonFactory;
 
-import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
-import org.projectfloodlight.openflow.types.IPv4Address;
-import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.TransportPort;
 import org.projectfloodlight.openflow.types.U64;
-import org.projectfloodlight.openflow.types.VlanPcp;
-import org.projectfloodlight.openflow.types.VlanVid;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
-import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetNwTos;
-import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
-import org.projectfloodlight.openflow.protocol.action.OFActionStripVlan;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetTpDst;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetTpSrc;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
-import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
 
 /**
  * Represents static flow entries to be maintained by the controller on the 
@@ -69,775 +46,364 @@ import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
  */
 @LogMessageCategory("Static Flow Pusher")
 public class StaticFlowEntries {
-    protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class);
-    
-    private static class SubActionStruct {
-        OFAction action;
-    }
-        
-    /**
-     * This function generates a random hash for the bottom half of the cookie
-     * 
-     * @param fm
-     * @param userCookie
-     * @param name
-     * @return A cookie that encodes the application ID and a hash
-     */
-    public static U64 computeEntryCookie(OFFlowMod fm, int userCookie, String name) {
-        // flow-specific hash is next 20 bits LOOK! who knows if this 
-        int prime = 211;
-        int flowHash = 2311;
-        for (int i=0; i < name.length(); i++)
-            flowHash = flowHash * prime + (int)name.charAt(i);
-
-        return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash);
-    }
-    
-    /**
-     * Sets defaults for an OFFlowMod
-     * @param fm The OFFlowMod to set defaults for
-     * @param entryName The name of the entry. Used to compute the cookie.
-     */
-    public static OFFlowMod initDefaultFlowMod(OFFlowMod fm, String entryName) {
-        return fm.createBuilder().setIdleTimeout((short) 0)   // infinite
-        .setHardTimeout((short) 0)  // infinite
-        .setBufferId(OFBufferId.NO_BUFFER)
-        .setOutPort(OFPort.ANY) 
-        .setCookie(computeEntryCookie(fm, 0, entryName))
-        .setPriority(Integer.MAX_VALUE)
-        .build();
-    }
-    
-    /**
-     * Gets the entry name of a flow mod
-     * @param fmJson The OFFlowMod in a JSON representation
-     * @return The name of the OFFlowMod, null if not found
-     * @throws IOException If there was an error parsing the JSON
-     */
-    public static String getEntryNameFromJson(String fmJson) throws IOException{
-        MappingJsonFactory f = new MappingJsonFactory();
-        JsonParser jp;
-        
-        try {
-            jp = f.createJsonParser(fmJson);
-        } catch (JsonParseException e) {
-            throw new IOException(e);
-        }
-        
-        jp.nextToken();
-        if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
-            throw new IOException("Expected START_OBJECT");
-        }
-        
-        while (jp.nextToken() != JsonToken.END_OBJECT) {
-            if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
-                throw new IOException("Expected FIELD_NAME");
-            }
-            
-            String n = jp.getCurrentName();
-            jp.nextToken();
-            if (jp.getText().equals("")) 
-                continue;
-            
-            if (n == "name")
-                return jp.getText();
-        }
-        
-        return null;
-    }
-    
-    /**
-     * Parses an OFFlowMod (and it's inner OFMatch) to the storage entry format.
-     * @param fm The FlowMod to parse
-     * @param sw The switch the FlowMod is going to be installed on
-     * @param name The name of this static flow entry
-     * @return A Map representation of the storage entry 
-     */
-    public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) {
-        Map<String, Object> entry = new HashMap<String, Object>();
-        Match match = fm.getMatch();
-        entry.put(StaticFlowEntryPusher.COLUMN_NAME, name);
-        entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw);
-        entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
-        entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Integer.toString(fm.getPriority()));
-        //entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, Integer.toString(match.getWildcards())); TODO @Ryan what to do about wildcards?
-        
-        if ((fm.getActions() != null) && (fm.getActions().size() > 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, StaticFlowEntries.flowModActionsToString(fm.getActions()));
-        
-        if ((match.get(MatchField.IN_PORT) != null) && (match.get(MatchField.IN_PORT).getPortNumber() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Integer.toString(match.get(MatchField.IN_PORT).getPortNumber()));
-        
-        if ((match.get(MatchField.ETH_SRC) != null) && !match.get(MatchField.ETH_SRC).equals(MacAddress.of(0)))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, match.get(MatchField.ETH_SRC).toString());
-
-        if ((match.get(MatchField.ETH_DST) != null) && !match.get(MatchField.ETH_DST).equals(MacAddress.of(0)))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, match.get(MatchField.ETH_DST).toString());
-        
-        if ((match.get(MatchField.VLAN_VID) != null) && (match.get(MatchField.VLAN_VID).getVlan() != -1))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, match.get(MatchField.VLAN_VID).toString());
-        
-        if ((match.get(MatchField.VLAN_PCP) != null) && (match.get(MatchField.VLAN_PCP).getValue() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Byte.toString(match.get(MatchField.VLAN_PCP).getValue()));
-        
-        if ((match.get(MatchField.ETH_TYPE) != null) && (match.get(MatchField.ETH_TYPE).getValue() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, match.get(MatchField.ETH_TYPE).toString());
-        
-        if ((match.get(MatchField.IP_ECN) != null) && (match.get(MatchField.IP_DSCP) != null) 
-        		&& (match.get(MatchField.IP_ECN).getEcnValue() != 0) && (match.get(MatchField.IP_DSCP).getDscpValue() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, // TOS = [DSCP bits 0-5] + [ECN bits 6-7] --> bitwise OR to get TOS byte
-        			Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue() | match.get(MatchField.IP_DSCP).getDscpValue())));
-        
-        if ((match.get(MatchField.IP_PROTO) != null) && (match.get(MatchField.IP_PROTO).getIpProtocolNumber() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.get(MatchField.IP_PROTO).getIpProtocolNumber()));
-        
-        if ((match.get(MatchField.IPV4_SRC) != null) && (match.get(MatchField.IPV4_SRC).getInt() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, match.get(MatchField.IPV4_SRC).toString());
-        
-        if ((match.get(MatchField.IPV4_DST) != null) && (match.get(MatchField.IPV4_DST).getInt() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, match.get(MatchField.IPV4_DST).toString());
-        
-        if ((match.get(MatchField.TCP_SRC) != null) && (match.get(MatchField.TCP_SRC).getPort() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.TCP_SRC).toString());
-        else if ((match.get(MatchField.UDP_SRC) != null) && (match.get(MatchField.UDP_SRC).getPort() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.UDP_SRC).toString());
-        else if ((match.get(MatchField.SCTP_SRC) != null) && (match.get(MatchField.SCTP_SRC).getPort() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.SCTP_SRC).toString());
-        
-        if ((match.get(MatchField.TCP_DST) != null) && (match.get(MatchField.TCP_DST).getPort() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.TCP_DST).toString());
-        else if ((match.get(MatchField.UDP_DST) != null) && (match.get(MatchField.UDP_DST).getPort() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.UDP_DST).toString());
-        else if ((match.get(MatchField.SCTP_DST) != null) && (match.get(MatchField.SCTP_DST).getPort() != 0))
-        	entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.SCTP_DST).toString());
-        
-        return entry;
-    }
-    
-    /**
-     * Returns a String representation of all the openflow actions.
-     * @param fmActions A list of OFActions to encode into one string
-     * @return A string of the actions encoded for our database
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Could not decode action {action}",
-            explanation="A static flow entry contained an invalid action",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    private static String flowModActionsToString(List<OFAction> fmActions) {
-        StringBuilder sb = new StringBuilder();
-        for (OFAction a : fmActions) {
-            if (sb.length() > 0) {
-                sb.append(',');
-            }
-            switch(a.getType()) {
-                case OUTPUT:
-                    sb.append("output=" + ((OFActionOutput)a).getPort().toString());
-                    break;
-                case ENQUEUE:
-                    long queue = ((OFActionEnqueue)a).getQueueId();
-                    OFPort port = ((OFActionEnqueue)a).getPort();
-                    sb.append("enqueue=" + Integer.toString(port.getPortNumber()) + ":0x" + String.format("%02x", queue));
-                    break;
-                case STRIP_VLAN:
-                    sb.append("strip-vlan");
-                    break;
-                case SET_VLAN_VID:
-                    sb.append("set-vlan-id=" + 
-                        ((OFActionSetVlanVid)a).getVlanVid().toString());
-                    break;
-                case SET_VLAN_PCP:
-                    sb.append("set-vlan-priority=" +
-                        Byte.toString(((OFActionSetVlanPcp)a).getVlanPcp().getValue()));
-                    break;
-                case SET_DL_SRC:
-                    sb.append("set-src-mac=" + 
-                        ((OFActionSetDlSrc)a).getDlAddr().toString());
-                    break;
-                case SET_DL_DST:
-                    sb.append("set-dst-mac=" + 
-                        ((OFActionSetDlDst)a).getDlAddr().toString());
-                    break;
-                case SET_NW_TOS:
-                    sb.append("set-tos-bits=" +
-                        Short.toString(((OFActionSetNwTos)a).getNwTos()));
-                    break;
-                case SET_NW_SRC:
-                    sb.append("set-src-ip=" +
-                        ((OFActionSetNwSrc)a).getNwAddr().toString());
-                    break;
-                case SET_NW_DST:
-                    sb.append("set-dst-ip=" +
-                        ((OFActionSetNwDst)a).getNwAddr().toString());
-                    break;
-                case SET_TP_SRC:
-                    sb.append("set-src-port=" +
-                        ((OFActionSetTpSrc)a).getTpPort().toString());
-                    break;
-                case SET_TP_DST:
-                    sb.append("set-dst-port=" +
-                        ((OFActionSetTpDst)a).getTpPort().toString());
-                    break;
-                default:
-                    log.error("Could not decode action: {}", a);
-                    break;
-            }
-                
-        }
-        return sb.toString();
-    }
-    
-    /**
-     * Turns a JSON formatted Static Flow Pusher string into a storage entry
-     * Expects a string in JSON along the lines of:
-     *        {
-     *            "switch":       "AA:BB:CC:DD:EE:FF:00:11",
-     *            "name":         "flow-mod-1",
-     *            "cookie":       "0",
-     *            "priority":     "32768",
-     *            "ingress-port": "1",
-     *            "actions":      "output=2",
-     *        }
-     * @param fmJson The JSON formatted static flow pusher entry
-     * @return The map of the storage entry
-     * @throws IOException If there was an error parsing the JSON
-     */
-    public static Map<String, Object> jsonToStorageEntry(String fmJson) throws IOException {
-        Map<String, Object> entry = new HashMap<String, Object>();
-        MappingJsonFactory f = new MappingJsonFactory();
-        JsonParser jp;
-        
-        try {
-            jp = f.createJsonParser(fmJson);
-        } catch (JsonParseException e) {
-            throw new IOException(e);
-        }
-        
-        jp.nextToken();
-        if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
-            throw new IOException("Expected START_OBJECT");
-        }
-        
-        while (jp.nextToken() != JsonToken.END_OBJECT) {
-            if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
-                throw new IOException("Expected FIELD_NAME");
-            }
-            
-            String n = jp.getCurrentName();
-            jp.nextToken();
-            if (jp.getText().equals("")) 
-                continue;
-            
-            if (n == "name")
-                entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText());
-            else if (n == "switch")
-                entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText());
-            else if (n == "actions")
-                entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText());
-            else if (n == "priority")
-                entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText());
-            else if (n == "active")
-                entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText());
-            else if (n == "wildcards")
-                entry.put(StaticFlowEntryPusher.COLUMN_WILDCARD, jp.getText());
-            else if (n == "ingress-port")
-                entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText());
-            else if (n == "src-mac")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText());
-            else if (n == "dst-mac")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText());
-            else if (n == "vlan-id")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText());
-            else if (n == "vlan-priority")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText());
-            else if (n == "ether-type")
-                entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText());
-            else if (n == "tos-bits")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText());
-            else if (n == "protocol")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText());
-            else if (n == "src-ip")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText());
-            else if (n == "dst-ip")
-                entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText());
-            else if (n == "src-port")
-                entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText());
-            else if (n == "dst-port")
-                entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText());
-        }
-        
-        return entry;
-    }
-    
-    /**
-     * Parses OFFlowMod actions from strings.
-     * @param flowMod The OFFlowMod to set the actions for
-     * @param actionstr The string containing all the actions
-     * @param log A logger to log for errors.
-     */
-    @LogMessageDoc(level="ERROR",
-            message="Unexpected action '{action}', '{subaction}'",
-            explanation="A static flow entry contained an invalid action",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    public static OFFlowMod parseActionString(OFFlowMod flowMod, String actionstr, Logger log) {
-        List<OFAction> actions = new LinkedList<OFAction>();
-        if (actionstr != null) {
-            actionstr = actionstr.toLowerCase();
-            for (String subaction : actionstr.split(",")) {
-                String action = subaction.split("[=:]")[0];
-                SubActionStruct subaction_struct = null;
-                
-                if (action.equals("output")) {
-                    subaction_struct = StaticFlowEntries.decode_output(subaction, log);
-                }
-                else if (action.equals("enqueue")) {
-                    subaction_struct = decode_enqueue(subaction, log);
-                }
-                else if (action.equals("strip-vlan")) {
-                    subaction_struct = decode_strip_vlan(subaction, log);
-                }
-                else if (action.equals("set-vlan-id")) {
-                    subaction_struct = decode_set_vlan_id(subaction, log);
-                }
-                else if (action.equals("set-vlan-priority")) {
-                    subaction_struct = decode_set_vlan_priority(subaction, log);
-                }
-                else if (action.equals("set-src-mac")) {
-                    subaction_struct = decode_set_src_mac(subaction, log);
-                }
-                else if (action.equals("set-dst-mac")) {
-                    subaction_struct = decode_set_dst_mac(subaction, log);
-                }
-                else if (action.equals("set-tos-bits")) {
-                    subaction_struct = decode_set_tos_bits(subaction, log);
-                }
-                else if (action.equals("set-src-ip")) {
-                    subaction_struct = decode_set_src_ip(subaction, log);
-                }
-                else if (action.equals("set-dst-ip")) {
-                    subaction_struct = decode_set_dst_ip(subaction, log);
-                }
-                else if (action.equals("set-src-port")) {
-                    subaction_struct = decode_set_src_port(subaction, log);
-                }
-                else if (action.equals("set-dst-port")) {
-                    subaction_struct = decode_set_dst_port(subaction, log);
-                }
-                else {
-                    log.error("Unexpected action '{}', '{}'", action, subaction);
-                }
-                
-                if (subaction_struct != null) {
-                    actions.add(subaction_struct.action);
-                }
-            }
-        }
-        log.debug("action {}", actions);
-        
-        return flowMod.createBuilder().setActions(actions).build();
-    } 
-    
-    @LogMessageDoc(level="ERROR",
-            message="Invalid subaction: '{subaction}'",
-            explanation="A static flow entry contained an invalid subaction",
-            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
-    private static SubActionStruct decode_output(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("output=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(subaction);
-        if (n.matches()) {
-            OFActionOutput.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput();
-            OFPort port = OFPort.ANY;
-            if (n.group(1) != null) {
-                try {
-                    port = OFPort.of(get_short(n.group(1)));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else if (n.group(2) != null)
-                port = OFPort.ALL;
-            else if (n.group(3) != null)
-                port = OFPort.CONTROLLER;
-            else if (n.group(4) != null)
-                port = OFPort.LOCAL;
-            else if (n.group(5) != null)
-                port = OFPort.IN_PORT;
-            else if (n.group(6) != null)
-                port = OFPort.NORMAL;
-            else if (n.group(7) != null)
-                port = OFPort.FLOOD;
-            ab.setPort(port);
-            log.debug("action {}", ab.build());
-            
-            sa = new SubActionStruct();
-            sa.action = ab.build();
-        }
-        else {
-            log.error("Invalid subaction: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_enqueue(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n;
-        
-        n = Pattern.compile("enqueue=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(subaction);
-        if (n.matches()) {
-            OFPort port = OFPort.of(0);
-            if (n.group(1) != null) {
-                try {
-                    port = OFPort.of(get_short(n.group(1)));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid port-num in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-
-            int queueid = 0;
-            if (n.group(2) != null) {
-                try {
-                    queueid = get_int(n.group(2));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid queue-id in: '{}' (error ignored)", subaction);
-                    return null;
-               }
-            }
-            
-            OFActionEnqueue.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildEnqueue();
-            ab.setPort(port);
-            ab.setQueueId(queueid);
-            log.debug("action {}", ab.build());
-            
-            sa = new SubActionStruct();
-            sa.action = ab.build();
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-        
-        return sa;
-    }
-    
-    private static SubActionStruct decode_strip_vlan(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("strip-vlan").matcher(subaction);
-        
-        if (n.matches()) {
-            OFActionStripVlan a = OFFactories.getFactory(OFVersion.OF_13).actions().stripVlan();
-            log.debug("action {}", a);
-            
-            sa = new SubActionStruct();
-            sa.action = a;
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_id(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-id=((?:0x)?\\d+)").matcher(subaction);
-        
-        if (n.matches()) {            
-            if (n.group(1) != null) {
-                try {
-                    VlanVid vlanid = VlanVid.ofVlan(get_short(n.group(1)));
-                    OFActionSetVlanVid.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetVlanVid();
-                    ab.setVlanVid(vlanid);
-                    log.debug("  action {}", ab.build());
-
-                    sa = new SubActionStruct();
-                    sa.action = ab.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }          
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_vlan_priority(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-vlan-priority=((?:0x)?\\d+)").matcher(subaction); 
-        
-        if (n.matches()) {            
-            if (n.group(1) != null) {
-                try {
-                    VlanPcp prior = VlanPcp.of(get_byte(n.group(1)));
-                    OFActionSetVlanPcp.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetVlanPcp();
-                    ab.setVlanPcp(prior);
-                    log.debug("  action {}", ab.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = ab.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid VLAN priority in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_mac(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction); 
-
-        if (n.matches()) {
-            MacAddress macaddr = MacAddress.of(get_mac_addr(n, subaction, log));
-            if (macaddr != null) {
-                OFActionSetDlSrc.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetDlSrc();
-                ab.setDlAddr(macaddr);
-                log.debug("action {}", ab.build());
-
-                sa = new SubActionStruct();
-                sa.action = ab.build();
-            }            
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_mac(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-mac=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(subaction);
-        
-        if (n.matches()) {
-            MacAddress macaddr = MacAddress.of(get_mac_addr(n, subaction, log));            
-            if (macaddr != null) {
-                OFActionSetDlDst.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetDlDst();
-                ab.setDlAddr(macaddr);
-                log.debug("  action {}", ab.build());
-                
-                sa = new SubActionStruct();
-                sa.action = ab.build();
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_tos_bits(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-tos-bits=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    byte tosbits = get_byte(n.group(1));
-                    OFActionSetNwTos.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetNwTos();
-                    ab.setNwTos(tosbits);
-                    log.debug("  action {}", ab.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = ab.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-    
-    private static SubActionStruct decode_set_src_ip(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            IPv4Address ipaddr = IPv4Address.of(get_ip_addr(n, subaction, log));
-            OFActionSetNwSrc.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetNwSrc();
-            ab.setNwAddr(ipaddr);
-            log.debug("  action {}", ab.build());
-
-            sa = new SubActionStruct();
-            sa.action = ab.build();
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_ip(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-ip=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(subaction);
-
-        if (n.matches()) {
-            IPv4Address ipaddr = IPv4Address.of(get_ip_addr(n, subaction, log));
-            OFActionSetNwDst.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetNwDst();
-            ab.setNwAddr(ipaddr);
-            log.debug("action {}", ab.build());
- 
-            sa = new SubActionStruct();
-            sa.action = ab.build();
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_src_port(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-src-port=((?:0x)?\\d+)").matcher(subaction); 
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    TransportPort portnum = TransportPort.of(get_short(n.group(1)));
-                    OFActionSetTpSrc.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetTpSrc();
-                    ab.setTpPort(portnum);
-                    log.debug("action {}", ab.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = ab.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static SubActionStruct decode_set_dst_port(String subaction, Logger log) {
-        SubActionStruct sa = null;
-        Matcher n = Pattern.compile("set-dst-port=((?:0x)?\\d+)").matcher(subaction);
-
-        if (n.matches()) {
-            if (n.group(1) != null) {
-                try {
-                    TransportPort portnum = TransportPort.of(get_short(n.group(1)));
-                    OFActionSetTpDst.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetTpDst();
-                    ab.setTpPort(portnum);
-                    log.debug("action {}", ab.build());
-                    
-                    sa = new SubActionStruct();
-                    sa.action = ab.build();
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid dst-port in: {} (error ignored)", subaction);
-                    return null;
-                }
-            }
-        }
-        else {
-            log.debug("Invalid action: '{}'", subaction);
-            return null;
-        }
-
-        return sa;
-    }
-
-    private static byte[] get_mac_addr(Matcher n, String subaction, Logger log) {
-        byte[] macaddr = new byte[6];
-        
-        for (int i=0; i<6; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    macaddr[i] = get_byte("0x" + n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-mac in: '{}' (error ignored)", subaction);
-                    return null;
-                }
-            }
-            else { 
-                log.debug("Invalid src-mac in: '{}' (null, error ignored)", subaction);
-                return null;
-            }
-        }
-        
-        return macaddr;
-    }
-    
-    private static int get_ip_addr(Matcher n, String subaction, Logger log) {
-        int ipaddr = 0;
-
-        for (int i=0; i<4; i++) {
-            if (n.group(i+1) != null) {
-                try {
-                    ipaddr = ipaddr<<8;
-                    ipaddr = ipaddr | get_int(n.group(i+1));
-                }
-                catch (NumberFormatException e) {
-                    log.debug("Invalid src-ip in: '{}' (error ignored)", subaction);
-                    return 0;
-                }
-            }
-            else {
-                log.debug("Invalid src-ip in: '{}' (null, error ignored)", subaction);
-                return 0;
-            }
-        }
-        
-        return ipaddr;
-    }
-    
-    // Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static int get_int(String str) {
-        return Integer.decode(str);
-    }
-   
-    // Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static short get_short(String str) {
-        return (short)(int)Integer.decode(str);
-    }
-   
-    // Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
-    private static byte get_byte(String str) {
-        return Integer.decode(str).byteValue();
-    }
-
+	protected static Logger log = LoggerFactory.getLogger(StaticFlowEntries.class);
+	private static final int INFINITE_TIMEOUT = 0;
+
+	/**
+	 * This function generates a random hash for the bottom half of the cookie
+	 * 
+	 * @param fm
+	 * @param userCookie
+	 * @param name
+	 * @return A cookie that encodes the application ID and a hash
+	 */
+	public static U64 computeEntryCookie(int userCookie, String name) {
+		// flow-specific hash is next 20 bits LOOK! who knows if this 
+		int prime = 211;
+		int flowHash = 2311;
+		for (int i=0; i < name.length(); i++) {
+			flowHash = flowHash * prime + (int)name.charAt(i);
+		}
+
+		return AppCookie.makeCookie(StaticFlowEntryPusher.STATIC_FLOW_APP_ID, flowHash);
+	}
+
+	/**
+	 * Sets defaults for an OFFlowMod used in the StaticFlowEntryPusher
+	 * @param fm The OFFlowMod to set defaults for
+	 * @param entryName The name of the entry. Used to compute the cookie.
+	 */
+	public static void initDefaultFlowMod(OFFlowMod.Builder fmb, String entryName) {
+		fmb.setIdleTimeout(INFINITE_TIMEOUT) // not setting these would also work
+		.setHardTimeout(INFINITE_TIMEOUT)
+		.setBufferId(OFBufferId.NO_BUFFER)
+		.setOutPort(OFPort.ANY) 
+		.setCookie(computeEntryCookie(0, entryName))
+		.setPriority(Integer.MAX_VALUE);
+		return;
+	}
+
+	/**
+	 * Gets the entry name of a flow mod
+	 * @param fmJson The OFFlowMod in a JSON representation
+	 * @return The name of the OFFlowMod, null if not found
+	 * @throws IOException If there was an error parsing the JSON
+	 */
+	public static String getEntryNameFromJson(String fmJson) throws IOException{
+		MappingJsonFactory f = new MappingJsonFactory();
+		JsonParser jp;
+
+		try {
+			jp = f.createJsonParser(fmJson);
+		} catch (JsonParseException e) {
+			throw new IOException(e);
+		}
+
+		jp.nextToken();
+		if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
+			throw new IOException("Expected START_OBJECT");
+		}
+
+		while (jp.nextToken() != JsonToken.END_OBJECT) {
+			if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
+				throw new IOException("Expected FIELD_NAME");
+			}
+
+			String n = jp.getCurrentName();
+			jp.nextToken();
+			if (jp.getText().equals("")) 
+				continue;
+
+			if (n == StaticFlowEntryPusher.COLUMN_NAME)
+				return jp.getText();
+		}
+		return null;
+	}
+
+	/**
+	 * Parses an OFFlowMod (and it's inner Match) to the storage entry format.
+	 * @param fm The FlowMod to parse
+	 * @param sw The switch the FlowMod is going to be installed on
+	 * @param name The name of this static flow entry
+	 * @return A Map representation of the storage entry 
+	 */
+	public static Map<String, Object> flowModToStorageEntry(OFFlowMod fm, String sw, String name) {
+		Map<String, Object> entry = new HashMap<String, Object>();
+		entry.put(StaticFlowEntryPusher.COLUMN_NAME, name);
+		entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, sw);
+		entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, Boolean.toString(true));
+		entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, Integer.toString(fm.getPriority()));
+
+		if ((fm.getActions() != null) && (fm.getActions().size() > 0)) {
+			entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, ActionUtils.actionsToString(fm.getActions(), log));
+		}
+
+		Match match = fm.getMatch();
+		boolean setTOS = false;
+		Iterator<MatchField<?>> itr = match.getMatchFields().iterator(); // only get exact or masked fields (not fully wildcarded)
+		while(itr.hasNext()) {
+			@SuppressWarnings("rawtypes") // this is okay here
+			MatchField mf = itr.next();
+			switch (mf.id) {
+			case IN_PORT: // iterates over only exact/masked fields. No need to check for null entries.
+				entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, Integer.toString((match.get(MatchField.IN_PORT)).getPortNumber()));
+				break;
+			case ETH_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, match.get(MatchField.ETH_SRC).toString());
+				break;
+			case ETH_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, match.get(MatchField.ETH_DST).toString());
+				break;
+			case VLAN_VID:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, match.get(MatchField.VLAN_VID).getVlan());
+				break;
+			case VLAN_PCP:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, Byte.toString(match.get(MatchField.VLAN_PCP).getValue()));
+				break;
+			case ETH_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, match.get(MatchField.ETH_TYPE).getValue());
+				break;
+			case IP_ECN: // TOS = [DSCP bits 0-5] + [ECN bits 6-7] --> bitwise OR to get TOS byte
+				if (setTOS) { //TODO @Ryan need to break TOS into ECN and DSCP columns
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, 
+							Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue() 
+									| (Byte.parseByte(entry.get(StaticFlowEntryPusher.COLUMN_NW_TOS).toString())))));
+				} else {
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue())));
+				}
+				setTOS = true;
+				break;
+			case IP_DSCP:
+				if (setTOS) {
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, 
+							Byte.toString((byte) (match.get(MatchField.IP_DSCP).getDscpValue() 
+									| (Byte.parseByte(entry.get(StaticFlowEntryPusher.COLUMN_NW_TOS).toString())))));
+				} else {
+					entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, Byte.toString((byte) (match.get(MatchField.IP_ECN).getEcnValue())));
+				}
+				setTOS = true;
+				break;
+			case IP_PROTO:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, Short.toString(match.get(MatchField.IP_PROTO).getIpProtocolNumber()));
+				break;
+			case IPV4_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, match.get(MatchField.IPV4_SRC).toString());
+				break;
+			case IPV4_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, match.get(MatchField.IPV4_DST).toString());
+				break;
+			case TCP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.TCP_SRC).getPort());
+				break;
+			case UDP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.UDP_SRC).getPort());
+				break;
+			case SCTP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, match.get(MatchField.SCTP_SRC).getPort());
+				break;
+			case TCP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.TCP_DST).getPort());
+				break;
+			case UDP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.UDP_DST).getPort());
+				break;
+			case SCTP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, match.get(MatchField.SCTP_DST).getPort());
+				break;
+			case ICMPV4_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_TYPE, match.get(MatchField.ICMPV4_TYPE).getType());
+				break;
+			case ICMPV4_CODE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_CODE, match.get(MatchField.ICMPV4_CODE).getCode());
+				break;
+			case ARP_OP:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_OPCODE, match.get(MatchField.ARP_OP).getOpcode());
+				break;
+			case ARP_SHA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SHA, match.get(MatchField.ARP_SHA).toString());
+				break;
+			case ARP_THA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DHA, match.get(MatchField.ARP_THA).toString());
+				break;
+			case ARP_SPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SPA, match.get(MatchField.ARP_SPA).toString());
+				break;
+			case ARP_TPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DPA, match.get(MatchField.ARP_TPA).toString());
+				break;
+			case MPLS_LABEL:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_LABEL, match.get(MatchField.MPLS_LABEL).getValue());
+				break;
+			case MPLS_TC:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_TC, match.get(MatchField.MPLS_TC).getValue());
+				break;
+				// case MPLS_BOS not implemented in loxi
+			case METADATA:
+				entry.put(StaticFlowEntryPusher.COLUMN_METADATA, match.get(MatchField.METADATA).getValue().getValue());
+				break;
+				// case TUNNEL_ID not implemented in loxi
+				// case PBB_ISID not implemented in loxi
+			default:
+				log.error("Unhandled Match when parsing OFFlowMod: {}, {}", mf, mf.id);
+				break;
+			} // end switch-case
+		} // end while
+		return entry;
+	}
+
+	/**
+	 * Turns a JSON formatted Static Flow Pusher string into a storage entry
+	 * Expects a string in JSON along the lines of:
+	 *        {
+	 *            "switch":       "AA:BB:CC:DD:EE:FF:00:11",
+	 *            "name":         "flow-mod-1",
+	 *            "cookie":       "0",
+	 *            "priority":     "32768",
+	 *            "ingress-port": "1",
+	 *            "actions":      "output=2",
+	 *        }
+	 * @param fmJson The JSON formatted static flow pusher entry
+	 * @return The map of the storage entry
+	 * @throws IOException If there was an error parsing the JSON
+	 */
+	public static Map<String, Object> jsonToStorageEntry(String fmJson) throws IOException {
+		Map<String, Object> entry = new HashMap<String, Object>();
+		MappingJsonFactory f = new MappingJsonFactory();
+		JsonParser jp;
+
+		try {
+			jp = f.createJsonParser(fmJson);
+		} catch (JsonParseException e) {
+			throw new IOException(e);
+		}
+
+		jp.nextToken();
+		if (jp.getCurrentToken() != JsonToken.START_OBJECT) {
+			throw new IOException("Expected START_OBJECT");
+		}
+
+		while (jp.nextToken() != JsonToken.END_OBJECT) {
+			if (jp.getCurrentToken() != JsonToken.FIELD_NAME) {
+				throw new IOException("Expected FIELD_NAME");
+			}
+
+			String n = jp.getCurrentName();
+			jp.nextToken();
+			if (jp.getText().equals("")) {
+				continue;
+			}
+
+			// Java 7 switch-case on strings automatically checks for (deep) string equality.
+			// IMHO, this makes things easier on the eyes than if, else if, else's
+
+			// A simplification is to make the column names the same strings as those used to
+			// compose the JSON flow entry; keeps all names/keys centralized and reduces liklihood
+			// for future string errors.
+			switch (n) {
+			case StaticFlowEntryPusher.COLUMN_NAME:
+				entry.put(StaticFlowEntryPusher.COLUMN_NAME, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_SWITCH:
+				entry.put(StaticFlowEntryPusher.COLUMN_SWITCH, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ACTIVE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ACTIVE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_IDLE_TIMEOUT: // store TO's, but conditionally push them
+				entry.put(StaticFlowEntryPusher.COLUMN_IDLE_TIMEOUT, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_HARD_TIMEOUT:
+				entry.put(StaticFlowEntryPusher.COLUMN_HARD_TIMEOUT, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_PRIORITY:
+				entry.put(StaticFlowEntryPusher.COLUMN_PRIORITY, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_COOKIE: // set manually, or computed from name
+				entry.put(StaticFlowEntryPusher.COLUMN_COOKIE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_IN_PORT:
+				entry.put(StaticFlowEntryPusher.COLUMN_IN_PORT, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_SRC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_DST, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_VLAN:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_VLAN_PCP, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_DL_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_DL_TYPE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_TOS:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_TOS, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_PROTO:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_PROTO, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_SRC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_NW_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_NW_DST, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_TP_SRC:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_SRC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_TP_DST:
+				entry.put(StaticFlowEntryPusher.COLUMN_TP_DST, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ICMP_TYPE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_TYPE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ICMP_CODE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ICMP_CODE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_OPCODE:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_OPCODE, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_SHA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SHA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_DHA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DHA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_SPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_SPA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ARP_DPA:
+				entry.put(StaticFlowEntryPusher.COLUMN_ARP_DPA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_MPLS_LABEL:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_LABEL, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_MPLS_TC:
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_TC, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_MPLS_BOS: // not supported as match in loxi right now
+				entry.put(StaticFlowEntryPusher.COLUMN_MPLS_BOS, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_METADATA:
+				entry.put(StaticFlowEntryPusher.COLUMN_METADATA, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_TUNNEL_ID: // not supported as match in loxi right now
+				entry.put(StaticFlowEntryPusher.COLUMN_TUNNEL_ID, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_PBB_ISID: // not supported as match in loxi right now
+				entry.put(StaticFlowEntryPusher.COLUMN_PBB_ISID, jp.getText());
+				break;
+			case StaticFlowEntryPusher.COLUMN_ACTIONS:
+				entry.put(StaticFlowEntryPusher.COLUMN_ACTIONS, jp.getText());
+				break;
+			default:
+				log.error("Could not decode field from JSON string: {}", n);
+			}  
+		}       
+		return entry;
+	}   
 }
 
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
index 48e7dfd8ab8d4a36dac83c2503630711c48d6664..66300be1ed663116829131f8be8e81cfedb45f01 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/StaticFlowEntryPusher.java
@@ -50,8 +50,9 @@ import net.floodlightcontroller.storage.IResultSet;
 import net.floodlightcontroller.storage.IStorageSourceListener;
 import net.floodlightcontroller.storage.IStorageSourceService;
 import net.floodlightcontroller.storage.StorageException;
+import net.floodlightcontroller.util.ActionUtils;
 import net.floodlightcontroller.util.FlowModUtils;
-import net.floodlightcontroller.util.MatchString;
+import net.floodlightcontroller.util.MatchUtils;
 
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
@@ -60,7 +61,6 @@ import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 import org.projectfloodlight.openflow.protocol.OFFlowRemovedReason;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
-import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFType;
 import org.projectfloodlight.openflow.types.DatapathId;
@@ -87,34 +87,66 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 
 	public static final String TABLE_NAME = "controller_staticflowtableentry";
 	public static final String COLUMN_NAME = "name";
-	public static final String COLUMN_SWITCH = "switch_id";
+	public static final String COLUMN_SWITCH = "switch";
 	public static final String COLUMN_ACTIVE = "active";
 	public static final String COLUMN_IDLE_TIMEOUT = "idle_timeout";
 	public static final String COLUMN_HARD_TIMEOUT = "hard_timeout";
 	public static final String COLUMN_PRIORITY = "priority";
 	public static final String COLUMN_COOKIE = "cookie";
-	public static final String COLUMN_WILDCARD = "wildcards";
-	public static final String COLUMN_IN_PORT = "in_port";
-	public static final String COLUMN_DL_SRC = "dl_src";
-	public static final String COLUMN_DL_DST = "dl_dst";
-	public static final String COLUMN_DL_VLAN = "dl_vlan";
-	public static final String COLUMN_DL_VLAN_PCP = "dl_vlan_pcp";
-	public static final String COLUMN_DL_TYPE = "dl_type";
-	public static final String COLUMN_NW_TOS = "nw_tos";
-	public static final String COLUMN_NW_PROTO = "nw_proto";
-	public static final String COLUMN_NW_SRC = "nw_src"; // includes CIDR-style
-	// netmask, e.g.
-	// "128.8.128.0/24"
-	public static final String COLUMN_NW_DST = "nw_dst";
-	public static final String COLUMN_TP_DST = "tp_dst";
-	public static final String COLUMN_TP_SRC = "tp_src";
+
+	// Common location for Match Strings. Still the same, but relocated.
+	public static final String COLUMN_IN_PORT = MatchUtils.STR_IN_PORT;
+
+	public static final String COLUMN_DL_SRC = MatchUtils.STR_DL_SRC;
+	public static final String COLUMN_DL_DST = MatchUtils.STR_DL_DST;
+	public static final String COLUMN_DL_VLAN = MatchUtils.STR_DL_VLAN;
+	public static final String COLUMN_DL_VLAN_PCP = MatchUtils.STR_DL_VLAN_PCP;
+	public static final String COLUMN_DL_TYPE = MatchUtils.STR_DL_TYPE;
+
+	public static final String COLUMN_NW_TOS = MatchUtils.STR_NW_TOS;
+	public static final String COLUMN_NW_PROTO = MatchUtils.STR_NW_PROTO;
+	public static final String COLUMN_NW_SRC = MatchUtils.STR_NW_SRC; // includes CIDR-style netmask, e.g. "128.8.128.0/24"
+	public static final String COLUMN_NW_DST = MatchUtils.STR_NW_DST;
+
+	public static final String COLUMN_TP_SRC = MatchUtils.STR_TP_SRC;
+	public static final String COLUMN_TP_DST = MatchUtils.STR_TP_DST;
+
+	/* newly added matches for OF1.3 port start here */
+	public static final String COLUMN_ICMP_TYPE = MatchUtils.STR_ICMP_TYPE;
+	public static final String COLUMN_ICMP_CODE = MatchUtils.STR_ICMP_CODE;
+
+	public static final String COLUMN_ARP_OPCODE = MatchUtils.STR_ARP_OPCODE;
+	public static final String COLUMN_ARP_SHA = MatchUtils.STR_ARP_SHA;
+	public static final String COLUMN_ARP_DHA = MatchUtils.STR_ARP_DHA;
+	public static final String COLUMN_ARP_SPA = MatchUtils.STR_ARP_SPA;
+	public static final String COLUMN_ARP_DPA = MatchUtils.STR_ARP_DPA;
+
+	public static final String COLUMN_MPLS_LABEL = MatchUtils.STR_MPLS_LABEL;
+	public static final String COLUMN_MPLS_TC = MatchUtils.STR_MPLS_TC;
+	public static final String COLUMN_MPLS_BOS = MatchUtils.STR_MPLS_BOS;
+
+	public static final String COLUMN_METADATA = MatchUtils.STR_METADATA;
+	public static final String COLUMN_TUNNEL_ID = MatchUtils.STR_TUNNEL_ID;
+
+	public static final String COLUMN_PBB_ISID = MatchUtils.STR_PBB_ISID;
+	/* end newly added matches TODO @Ryan should look into full IPv6 support*/
+
 	public static final String COLUMN_ACTIONS = "actions";
+
 	public static String ColumnNames[] = { COLUMN_NAME, COLUMN_SWITCH,
 		COLUMN_ACTIVE, COLUMN_IDLE_TIMEOUT, COLUMN_HARD_TIMEOUT,
-		COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_WILDCARD, COLUMN_IN_PORT,
+		COLUMN_PRIORITY, COLUMN_COOKIE, COLUMN_IN_PORT,
 		COLUMN_DL_SRC, COLUMN_DL_DST, COLUMN_DL_VLAN, COLUMN_DL_VLAN_PCP,
 		COLUMN_DL_TYPE, COLUMN_NW_TOS, COLUMN_NW_PROTO, COLUMN_NW_SRC,
-		COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, COLUMN_ACTIONS };
+		COLUMN_NW_DST, COLUMN_TP_DST, COLUMN_TP_SRC, 
+		/* newly added matches for OF1.3 port start here */
+		COLUMN_ICMP_TYPE, COLUMN_ICMP_CODE, 
+		COLUMN_ARP_OPCODE, COLUMN_ARP_SHA, COLUMN_ARP_DHA, 
+		COLUMN_ARP_SPA, COLUMN_ARP_DPA,
+		COLUMN_MPLS_LABEL, COLUMN_MPLS_TC, COLUMN_MPLS_BOS, 
+		COLUMN_METADATA, COLUMN_TUNNEL_ID, COLUMN_PBB_ISID,
+		/* end newly added matches */
+		COLUMN_ACTIONS };
 
 
 	protected IFloodlightProviderService floodlightProviderService;
@@ -140,7 +172,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 			OFFlowMod f1 = entriesFromStorage.get(dpid).get(o1);
 			OFFlowMod f2 = entriesFromStorage.get(dpid).get(o2);
 			if (f1 == null || f2 == null) // sort active=false flows by key
-					return o1.compareTo(o2);
+				return o1.compareTo(o2);
 			return U16.of(f1.getPriority()).getValue() - U16.of(f2.getPriority()).getValue();
 		}
 	};
@@ -240,8 +272,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 		try {
 			Map<String, Object> row;
 			// null1=no predicate, null2=no ordering
-			IResultSet resultSet = storageSourceService.executeQuery(TABLE_NAME,
-					ColumnNames, null, null);
+			IResultSet resultSet = storageSourceService.executeQuery(TABLE_NAME, ColumnNames, null, null);
 			for (Iterator<IResultSet> it = resultSet.iterator(); it.hasNext();) {
 				row = it.next().getRow();
 				parseRow(row, entries);
@@ -268,14 +299,10 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 		String entryName = null;
 
 		StringBuffer matchString = new StringBuffer();
-
-		OFFlowMod.Builder fmb = OFFactories.getFactory(OFVersion.OF_13).buildFlowModify();
-		OFFlowMod fm = fmb.build();
+		OFFlowMod.Builder fmb = null; 
 
 		if (!row.containsKey(COLUMN_SWITCH) || !row.containsKey(COLUMN_NAME)) {
-			log.debug(
-					"skipping entry with missing required 'switch' or 'name' entry: {}",
-					row);
+			log.debug("skipping entry with missing required 'switch' or 'name' entry: {}", row);
 			return;
 		}
 		// most error checking done with ClassCastException
@@ -283,9 +310,15 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 			// first, snag the required entries, for debugging info
 			switchName = (String) row.get(COLUMN_SWITCH);
 			entryName = (String) row.get(COLUMN_NAME);
-			if (!entries.containsKey(switchName))
+			if (!entries.containsKey(switchName)) {
 				entries.put(switchName, new HashMap<String, OFFlowMod>());
-			fm = StaticFlowEntries.initDefaultFlowMod(fm, entryName);
+			}
+
+			// get the correct builder for the OF version supported by the switch
+			// TODO @Ryan this should arguably be a FlowAdd, not a FlowModify
+			fmb = OFFactories.getFactory(switchService.getSwitch(DatapathId.of(switchName)).getOFFactory().getVersion()).buildFlowModify();
+
+			StaticFlowEntries.initDefaultFlowMod(fmb, entryName);
 
 			for (String key : row.keySet()) {
 				if (row.get(key) == null)
@@ -293,40 +326,33 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 				if (key.equals(COLUMN_SWITCH) || key.equals(COLUMN_NAME)
 						|| key.equals("id"))
 					continue; // already handled
-					// explicitly ignore timeouts and wildcards
-				if (key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT) ||
-						key.equals(COLUMN_WILDCARD))
+				// explicitly ignore timeouts and wildcards
+				if (key.equals(COLUMN_HARD_TIMEOUT) || key.equals(COLUMN_IDLE_TIMEOUT))
 					continue;
 				if (key.equals(COLUMN_ACTIVE)) {
 					if  (!Boolean.valueOf((String) row.get(COLUMN_ACTIVE))) {
-						log.debug("skipping inactive entry {} for switch {}",
-								entryName, switchName);
+						log.debug("skipping inactive entry {} for switch {}", entryName, switchName);
 						entries.get(switchName).put(entryName, null);  // mark this an inactive
 						return;
 					}
 				} else if (key.equals(COLUMN_ACTIONS)){
-					fm = StaticFlowEntries.parseActionString(fm, (String) row.get(COLUMN_ACTIONS), log);
+					ActionUtils.fromString(fmb, (String) row.get(COLUMN_ACTIONS), log);
 				} else if (key.equals(COLUMN_COOKIE)) {
-					fm = fm.createBuilder().setCookie(
-							StaticFlowEntries.computeEntryCookie(fm,
-									Integer.valueOf((String) row.get(COLUMN_COOKIE)),
-									entryName)).build();
+					fmb.setCookie(StaticFlowEntries.computeEntryCookie(Integer.valueOf((String) row.get(COLUMN_COOKIE)), entryName));
 				} else if (key.equals(COLUMN_PRIORITY)) {
-					fm = fm.createBuilder().setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY)))).build();
-				} else { // the rest of the keys are for OFMatch().fromString()
-					if (matchString.length() > 0)
+					fmb.setPriority(U16.t(Integer.valueOf((String) row.get(COLUMN_PRIORITY))));
+				} else { // the rest of the keys are for Match().fromString()
+					if (matchString.length() > 0) {
 						matchString.append(",");
-						matchString.append(key + "=" + row.get(key).toString());
+					}
+					matchString.append(key + "=" + row.get(key).toString());
 				}
 			}
 		} catch (ClassCastException e) {
 			if (entryName != null && switchName != null) {
-				log.warn(
-						"Skipping entry {} on switch {} with bad data : "
-								+ e.getMessage(), entryName, switchName);
+				log.warn("Skipping entry {} on switch {} with bad data : " + e.getMessage(), entryName, switchName);
 			} else {
-				log.warn("Skipping entry with bad data: {} :: {} ",
-						e.getMessage(), e.getStackTrace());
+				log.warn("Skipping entry with bad data: {} :: {} ", e.getMessage(), e.getStackTrace());
 			}
 		}
 
@@ -334,15 +360,13 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 
 		try {
 			//TODO @Ryan new fromString() method here. Should verify it especially
-			fm = fm.createBuilder().setMatch(MatchString.fromString(match, OFVersion.OF_13)).build();
+			fmb.setMatch(MatchUtils.fromString(match, fmb.getVersion()));
 		} catch (IllegalArgumentException e) {
-			log.debug(
-					"ignoring flow entry {} on switch {} with illegal OFMatch() key: "
-							+ match, entryName, switchName);
+			log.debug("ignoring flow entry {} on switch {} with illegal OFMatch() key: " + match, entryName, switchName);
 			return;
 		}
 
-		entries.get(switchName).put(entryName, fm);
+		entries.get(switchName).put(entryName, fmb.build()); // add the FlowMod message to the table
 	}
 
 	@Override
@@ -578,7 +602,7 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 		 * never expire.
 		 */
 		if (AppCookie.extractApp(cookie) == STATIC_FLOW_APP_ID) {
-			if (OFFlowRemovedReason.DELETE.equals(msg.getReason())) //TODO @Ryan getReason() --> short vs. enum???
+			if (OFFlowRemovedReason.DELETE.equals(msg.getReason()))
 				log.error("Got a FlowRemove message for a infinite " +
 						"timeout flow: {} from switch {}", msg, sw);
 			// Stop the processing chain since we sent the delete.
@@ -646,16 +670,11 @@ implements IOFSwitchListener, IFloodlightModule, IStaticFlowEntryPusherService,
 	}
 
 	@Override
-	public void init(FloodlightModuleContext context)
-			throws FloodlightModuleException {
-		floodlightProviderService =
-				context.getServiceImpl(IFloodlightProviderService.class);
-		switchService =
-				context.getServiceImpl(IOFSwitchService.class);
-		storageSourceService =
-				context.getServiceImpl(IStorageSourceService.class);
-		restApiService =
-				context.getServiceImpl(IRestApiService.class);
+	public void init(FloodlightModuleContext context) throws FloodlightModuleException {
+		floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
+		switchService = context.getServiceImpl(IOFSwitchService.class);
+		storageSourceService = context.getServiceImpl(IStorageSourceService.class);
+		restApiService = context.getServiceImpl(IRestApiService.class);
 		haListener = new HAListenerDelegate();
 	} 
 
diff --git a/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java b/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java
index 37a39bc864bbaefbd46543ff1d2ce6ab1cac5b72..d9ec69c1eba4f379fb8d02a18ba42f24a29e6118 100644
--- a/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java
+++ b/src/main/java/net/floodlightcontroller/staticflowentry/web/ListStaticFlowEntriesResource.java
@@ -47,14 +47,12 @@ public class ListStaticFlowEntriesResource extends ServerResource {
             return sfpService.getFlows();
         } else {
             try {
-                Map<String, Map<String, OFFlowMod>> retMap = 
-                        new HashMap<String, Map<String, OFFlowMod>>();
+                Map<String, Map<String, OFFlowMod>> retMap = new HashMap<String, Map<String, OFFlowMod>>();
                 retMap.put(param, sfpService.getFlows(DatapathId.of(param)));
                 return retMap;
                 
             } catch (NumberFormatException e){
-                setStatus(Status.CLIENT_ERROR_BAD_REQUEST, 
-                          ControllerSwitchesResource.DPID_ERROR);
+                setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ControllerSwitchesResource.DPID_ERROR);
             }
         }
         return null;
diff --git a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
index 7d55e68748e68e7de855bba2ed204d794d93b3ad..886a33750b3d0fb37b766c2b3eea2f1e59917405 100644
--- a/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
+++ b/src/main/java/net/floodlightcontroller/testmodule/TestModule.java
@@ -3,28 +3,61 @@ package net.floodlightcontroller.testmodule;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFOxmClass;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFSetConfig;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
+import org.projectfloodlight.openflow.types.ArpOpcode;
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.ICMPv4Code;
+import org.projectfloodlight.openflow.types.ICMPv4Type;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFBufferId;
+import org.projectfloodlight.openflow.types.OFMetadata;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFValueType;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import net.floodlightcontroller.core.IOFSwitchListener;
+import net.floodlightcontroller.core.PortChangeType;
+import net.floodlightcontroller.core.internal.IOFSwitchService;
 import net.floodlightcontroller.core.module.FloodlightModuleContext;
 import net.floodlightcontroller.core.module.FloodlightModuleException;
 import net.floodlightcontroller.core.module.IFloodlightModule;
 import net.floodlightcontroller.core.module.IFloodlightService;
 import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService;
 
-public class TestModule implements IFloodlightModule {
+public class TestModule implements IFloodlightModule, IOFSwitchListener {
 
 	private static IStaticFlowEntryPusherService sfps;
-	protected static Logger log;
+	private static IOFSwitchService switchService;
+	private static Logger log;
 	
 	@Override
 	public Collection<Class<? extends IFloodlightService>> getModuleServices() {
@@ -40,6 +73,7 @@ public class TestModule implements IFloodlightModule {
 	public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
 		Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>();
 		l.add(IStaticFlowEntryPusherService.class);
+		l.add(IOFSwitchService.class);
 		return l;
 	}
 
@@ -47,6 +81,8 @@ public class TestModule implements IFloodlightModule {
 	public void init(FloodlightModuleContext context)
 			throws FloodlightModuleException {
 		sfps = context.getServiceImpl(IStaticFlowEntryPusherService.class);
+		switchService = context.getServiceImpl(IOFSwitchService.class);
+		switchService.addOFSwitchListener(this);
 		log = LoggerFactory.getLogger(TestModule.class);
 		if (sfps == null) {
 			log.error("Static Flow Pusher Service not found!");
@@ -56,29 +92,99 @@ public class TestModule implements IFloodlightModule {
 	@Override
 	public void startUp(FloodlightModuleContext context)
 			throws FloodlightModuleException {
-		OFFlowAdd.Builder fmb = /*sw.getOFFactory()*/OFFactories.getFactory(OFVersion.OF_13).buildFlowAdd();
-        //Match.Builder mb = OFFactories.getFactory(OFVersion.OF_13).buildMatch();
-        
-        //fmb.setBufferId(OFBufferId.NO_BUFFER)
-        //fmb.setXid(pi.getXid());
-        /*.setMatch(pi.getMatch())*/
-
-        // set actions
-        OFActionOutput.Builder actionBuilder = /*sw.getOFFactory()*/OFFactories.getFactory(OFVersion.OF_13).actions().buildOutput();
-        actionBuilder.setPort(OFPort.ALL);
-        fmb.setActions(Collections.singletonList((OFAction) actionBuilder.build()));
-        fmb.setOutPort(OFPort.ALL);
 		
-		// we aren't matching anything specifically, so all should be wildcarded by default
-		// in on any port, with any header attributes, send out all ports = Hub module
-		try {
+
+	}
+
+	@Override
+	public void switchAdded(DatapathId switchId) {
+		OFFactory factory = switchService.getSwitch(switchId).getOFFactory();
+		OFFlowAdd.Builder fmb = factory.buildFlowAdd();
+		List<OFAction> actions = new ArrayList<OFAction>();
+        Match.Builder mb = factory.buildMatch();
+        
+		/*try {
 			Thread.sleep(3000);
 		} catch (InterruptedException e) {
 			e.printStackTrace();
-		}
-		sfps.addFlow("test-flow", fmb.build(), DatapathId.of(1)); // This should add the flow, regardless whether or not the switch is connected, I believe. If it connects in a second, it should be pushed.
+		}*/
+        
+        //TODO @Ryan set a bunch of matches. Test for an OF1.0 and OF1.3 switch. See what happens if they are incorrectly applied.
+        /* L2 and ICMP TESTS mb.setExact(MatchField.ETH_TYPE, EthType.IPv4);
+        mb.setExact(MatchField.ETH_SRC, MacAddress.BROADCAST);
+        mb.setExact(MatchField.ETH_DST, MacAddress.BROADCAST);
+        mb.setExact(MatchField.IPV4_SRC, IPv4Address.of("127.1.1.1"));
+        mb.setExact(MatchField.IPV4_DST, IPv4Address.of("128.2.2.2"));
+        mb.setExact(MatchField.IP_PROTO, IpProtocol.ICMP);
+        mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of((short)1));
+        mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.ECHO); */
+        
+        /* ARP TESTS mb.setExact(MatchField.ETH_TYPE, EthType.ARP);
+        mb.setExact(MatchField.ARP_OP, ArpOpcode.REQUEST);
+        mb.setExact(MatchField.ARP_SHA, MacAddress.BROADCAST);
+        mb.setExact(MatchField.ARP_SPA, IPv4Address.of("130.127.39.241"));
+        mb.setExact(MatchField.ARP_THA, MacAddress.BROADCAST);
+        mb.setExact(MatchField.ARP_TPA, IPv4Address.of("130.127.39.241")); */
+        
+        /* TP, IP OPT, VLAN TESTS */ mb.setExact(MatchField.ETH_TYPE, EthType.IPv4);
+        mb.setExact(MatchField.VLAN_PCP, VlanPcp.of((byte) 1)); // might as well test these now too
+        mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(512));
+        mb.setExact(MatchField.MPLS_LABEL, U32.of(32));
+        mb.setExact(MatchField.MPLS_TC, U8.of((short)64));
+        mb.setExact(MatchField.IP_ECN, IpEcn.ECN_10); // and these
+        mb.setExact(MatchField.IP_DSCP, IpDscp.DSCP_16);
+        mb.setExact(MatchField.IP_PROTO, IpProtocol.UDP); // with tcp, udp, sctp
+        mb.setExact(MatchField.UDP_SRC, TransportPort.of(22));
+        mb.setExact(MatchField.UDP_DST, TransportPort.of(80)); 
+        
+        /* MPLS TESTS mb.setExact(MatchField.ETH_TYPE, EthType.MPLS_MULTICAST);
+        mb.setExact(MatchField.MPLS_LABEL, U32.of(18));
+        mb.setExact(MatchField.MPLS_TC, U8.of((short)4));*/
+        
+        /* METADATA TEST 
+        mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(1)); */
+
+        
+        //TODO @Ryan set a bunch of actions. "" "" """ """"""
+        OFActionOutput.Builder actionBuilder = factory.actions().buildOutput();
+        actions.add(factory.actions().output(OFPort.of(1), Integer.MAX_VALUE));
+        actions.add(factory.actions().setField(factory.oxms().ethSrc(MacAddress.BROADCAST)));
+        actions.add(factory.actions().setField(factory.oxms().ethDst(MacAddress.BROADCAST)));
+        actions.add(factory.actions().setField(factory.oxms().ipv4Src(IPv4Address.of("127.0.1.2"))));
+        actions.add(factory.actions().setField(factory.oxms().ipv4Src(IPv4Address.of("128.0.3.4"))));
+
+
+        fmb.setActions(actions);
+        fmb.setMatch(mb.build());
+		        
+		sfps.addFlow("test-flow", fmb.build(), switchId);
 		//sfps.deleteFlow("test-flow");
+		
+	}
+
+	@Override
+	public void switchRemoved(DatapathId switchId) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void switchActivated(DatapathId switchId) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public void switchPortChanged(DatapathId switchId, OFPortDesc port,
+			PortChangeType type) {
+		// TODO Auto-generated method stub
+		
+	}
 
+	@Override
+	public void switchChanged(DatapathId switchId) {
+		// TODO Auto-generated method stub
+		
 	}
 
 }
diff --git a/src/main/java/net/floodlightcontroller/util/ActionUtils.java b/src/main/java/net/floodlightcontroller/util/ActionUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd6962531b5fbf42f3fd148b9bce5b6118e4b8bb
--- /dev/null
+++ b/src/main/java/net/floodlightcontroller/util/ActionUtils.java
@@ -0,0 +1,549 @@
+package net.floodlightcontroller.util;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import net.floodlightcontroller.core.annotations.LogMessageDoc;
+
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionEnqueue;
+import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetDlSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetNwTos;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetTpDst;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetTpSrc;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
+import org.projectfloodlight.openflow.protocol.action.OFActionStripVlan;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+
+/**
+ * OFAction helper functions. Use with any OpenFlowJ-Loxi Action.
+ * 
+ * Includes string methods refactored from StaticFlowEntryPusher
+ *
+ * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu>
+ */
+public class ActionUtils {
+	public static final String STR_OUTPUT = "output";
+	public static final String STR_ENQUEUE = "enqueue";
+	public static final String STR_VLAN_STRIP = "strip_vlan";
+	public static final String STR_VLAN_POP = "pop_vlan";
+	public static final String STR_VLAN_PUSH = "push_vlan";
+	public static final String STR_VLAN_SET_PCP = "set_vlan_priority";
+	public static final String STR_VLAN_SET_VID = "set_vlan_id";
+	public static final String STR_QUEUE_SET = "set_queue";
+	public static final String STR_DL_SRC_SET = "set_src_mac";
+	public static final String STR_DL_DST_SET = "set_dst_mac";
+	public static final String STR_NW_SRC_SET = "set_src_ip";
+	public static final String STR_NW_DST_SET = "set_dst_ip";
+	public static final String STR_NW_ECN_SET = "set_nw_ecn";
+	public static final String STR_NW_TOS_SET = "set_tos_bits";
+	public static final String STR_NW_TTL_SET = "set_ip_ttl";
+	public static final String STR_NW_TTL_DEC = "dec_ip_ttl";
+	public static final String STR_MPLS_LABEL_SET = "set_mpls_label";
+	public static final String STR_MPLS_TC_SET = "set_mpls_tc";
+	public static final String STR_MPLS_TTL_SET = "set_mpls_ttl";
+	public static final String STR_MPLS_TTL_DEC = "dec_mpls_ttl";
+	public static final String STR_MPLS_PUSH = "push_mpls";
+	public static final String STR_MPLS_POP = "pop_mpls";
+	public static final String STR_TP_SRC_SET = "set_src_port";
+	public static final String STR_TP_DST_SET = "set_dst_port";
+	public static final String STR_TTL_IN_COPY = "copy_ttl_in";
+	public static final String STR_TTL_OUT_COPY = "copy_ttl_out";
+	public static final String STR_PBB_PUSH = "push_pbb";
+	public static final String STR_PBB_POP = "pop_pbb";
+	public static final String STR_EXPERIMENTER = "experimenter";
+	public static final String STR_GROUP = "group";
+	public static final String STR_FIELD_SET = "set_field";
+
+	/**
+     * Returns a String representation of all the OpenFlow actions.
+     * @param actions A list of OFActions to encode into one string
+     * @return A dpctl-style string of the actions
+     */
+    @LogMessageDoc(level="ERROR",
+            message="Could not decode action {action}",
+            explanation="A static flow entry contained an invalid action",
+            recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+    public static String actionsToString(List<OFAction> actions, Logger log) {
+        StringBuilder sb = new StringBuilder();
+        for (OFAction a : actions) {
+            if (sb.length() > 0) {
+                sb.append(',');
+            }
+            switch(a.getType()) {
+                case OUTPUT:
+                    sb.append(STR_OUTPUT + "=" + ((OFActionOutput)a).getPort().toString());
+                    break;
+                case ENQUEUE:
+                    long queue = ((OFActionEnqueue)a).getQueueId();
+                    OFPort port = ((OFActionEnqueue)a).getPort();
+                    sb.append(STR_ENQUEUE + "=" + Integer.toString(port.getPortNumber()) + ":0x" + String.format("%02x", queue));
+                    break;
+                case STRIP_VLAN:
+                    sb.append(STR_VLAN_STRIP);
+                    break;
+                case SET_VLAN_VID:
+                    sb.append(STR_VLAN_SET_VID + "=" + 
+                        ((OFActionSetVlanVid)a).getVlanVid().toString());
+                    break;
+                case SET_VLAN_PCP:
+                    sb.append(STR_VLAN_SET_PCP + "=" +
+                        Byte.toString(((OFActionSetVlanPcp)a).getVlanPcp().getValue()));
+                    break;
+                case SET_DL_SRC:
+                    sb.append(STR_DL_SRC_SET + "=" + 
+                        ((OFActionSetDlSrc)a).getDlAddr().toString());
+                    break;
+                case SET_DL_DST:
+                    sb.append(STR_DL_DST_SET + "=" + 
+                        ((OFActionSetDlDst)a).getDlAddr().toString());
+                    break;
+                case SET_NW_TOS:
+                    sb.append(STR_NW_TOS_SET + "=" +
+                        Short.toString(((OFActionSetNwTos)a).getNwTos()));
+                    break;
+                case SET_NW_SRC:
+                    sb.append(STR_NW_SRC_SET + "=" +
+                        ((OFActionSetNwSrc)a).getNwAddr().toString());
+                    break;
+                case SET_NW_DST:
+                    sb.append(STR_NW_DST_SET + "=" +
+                        ((OFActionSetNwDst)a).getNwAddr().toString());
+                    break;
+                case SET_TP_SRC:
+                    sb.append(STR_TP_SRC_SET + "=" +
+                        ((OFActionSetTpSrc)a).getTpPort().toString());
+                    break;
+                case SET_TP_DST:
+                    sb.append(STR_TP_DST_SET + "=" +
+                        ((OFActionSetTpDst)a).getTpPort().toString());
+                    break;
+                default:
+                    log.error("Could not decode action: {}", a);
+                    break;
+            }
+                
+        }
+        return sb.toString();
+    }
+	
+	/**
+	 * Parses OFFlowMod actions from strings.
+	 * @param fmb The OFFlowMod.Builder to set the actions for
+	 * @param bigString The string containing all the actions
+	 * @param log A logger to log for errors.
+	 */
+	@LogMessageDoc(level="ERROR",
+			message="Unexpected action '{action}', '{subaction}'",
+			explanation="A static flow entry contained an invalid action",
+			recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	public static void fromString(OFFlowMod.Builder fmb, String bigString, Logger log) {
+		List<OFAction> actions = new LinkedList<OFAction>();
+		if (bigString != null) {
+			bigString = bigString.toLowerCase();
+			for (String actionToDecode : bigString.split(",")) {
+				String action = actionToDecode.split("[=:]")[0];
+				OFAction a = null;
+
+				if (action.equals(STR_OUTPUT)) {
+					a = decode_output(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_ENQUEUE)) {
+					a = decode_enqueue(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_VLAN_STRIP)) {
+					a = decode_strip_vlan(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_VLAN_SET_VID)) {
+					a = decode_set_vlan_id(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_VLAN_SET_PCP)) {
+					a = decode_set_vlan_priority(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_DL_SRC_SET)) {
+					a = decode_set_src_mac(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_DL_DST_SET)) {
+					a = decode_set_dst_mac(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_NW_TOS_SET)) {
+					a = decode_set_tos_bits(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_NW_SRC_SET)) {
+					a = decode_set_src_ip(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_NW_DST_SET)) {
+					a = decode_set_dst_ip(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_TP_SRC_SET)) {
+					a = decode_set_src_port(actionToDecode, fmb.getVersion(), log);
+				}
+				else if (action.equals(STR_TP_DST_SET)) {
+					a = decode_set_dst_port(actionToDecode, fmb.getVersion(), log);
+				}
+				else {
+					log.error("Unexpected action '{}', '{}'", action, actionToDecode);
+				}
+
+				if (a != null) {
+					actions.add(a);
+				}
+			}
+		}
+		log.debug("action {}", actions);
+
+		fmb.setActions(actions);
+		return;
+	} 
+
+	@LogMessageDoc(level="ERROR",
+			message="Invalid subaction: '{subaction}'",
+			explanation="A static flow entry contained an invalid subaction",
+			recommendation=LogMessageDoc.REPORT_CONTROLLER_BUG)
+	private static OFActionOutput decode_output(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_OUTPUT + 
+				"=(?:((?:0x)?\\d+)|(all)|(controller)|(local)|(ingress-port)|(normal)|(flood))").matcher(actionToDecode);
+		if (n.matches()) {
+			OFActionOutput.Builder ab = OFFactories.getFactory(version).actions().buildOutput();
+			OFPort port = OFPort.ANY;
+			if (n.group(1) != null) {
+				try {
+					port = OFPort.of(get_short(n.group(1)));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid port in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+			else if (n.group(2) != null)
+				port = OFPort.ALL;
+			else if (n.group(3) != null)
+				port = OFPort.CONTROLLER;
+			else if (n.group(4) != null)
+				port = OFPort.LOCAL;
+			else if (n.group(5) != null)
+				port = OFPort.IN_PORT;
+			else if (n.group(6) != null)
+				port = OFPort.NORMAL;
+			else if (n.group(7) != null)
+				port = OFPort.FLOOD;
+			ab.setPort(port);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.error("Invalid subaction: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionEnqueue decode_enqueue(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_ENQUEUE + "=(?:((?:0x)?\\d+)\\:((?:0x)?\\d+))").matcher(actionToDecode);
+		if (n.matches()) {
+			OFPort port = OFPort.of(0);
+			if (n.group(1) != null) {
+				try {
+					port = OFPort.of(get_short(n.group(1)));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid port-num in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+
+			int queueid = 0;
+			if (n.group(2) != null) {
+				try {
+					queueid = get_int(n.group(2));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid queue-id in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+			OFActionEnqueue.Builder ab = OFFactories.getFactory(version).actions().buildEnqueue();
+			ab.setPort(port);
+			ab.setQueueId(queueid);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionStripVlan decode_strip_vlan(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_VLAN_STRIP).matcher(actionToDecode);
+		if (n.matches()) {
+			OFActionStripVlan a = OFFactories.getFactory(version).actions().stripVlan();
+			log.debug("action {}", a);
+			return a;
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionSetVlanVid decode_set_vlan_id(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_VLAN_SET_VID + "=((?:0x)?\\d+)").matcher(actionToDecode);
+		if (n.matches()) {            
+			if (n.group(1) != null) {
+				try {
+					VlanVid vlanid = VlanVid.ofVlan(get_short(n.group(1)));
+					OFActionSetVlanVid.Builder ab = OFFactories.getFactory(version).actions().buildSetVlanVid();
+					ab.setVlanVid(vlanid);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid VLAN in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}          
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetVlanPcp decode_set_vlan_priority(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_VLAN_SET_PCP + "=((?:0x)?\\d+)").matcher(actionToDecode); 
+		if (n.matches()) {            
+			if (n.group(1) != null) {
+				try {
+					VlanPcp prior = VlanPcp.of(get_byte(n.group(1)));
+					OFActionSetVlanPcp.Builder ab = OFFactories.getFactory(OFVersion.OF_13).actions().buildSetVlanPcp();
+					ab.setVlanPcp(prior);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid VLAN priority in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetDlSrc decode_set_src_mac(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_DL_SRC_SET +
+				"=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(actionToDecode); 
+		if (n.matches()) {
+			MacAddress macaddr = MacAddress.of(get_mac_addr(n, actionToDecode, log));
+			if (macaddr != null) {
+				OFActionSetDlSrc.Builder ab = OFFactories.getFactory(version).actions().buildSetDlSrc();
+				ab.setDlAddr(macaddr);
+				log.debug("action {}", ab.build());
+				return ab.build();
+			}            
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetDlDst decode_set_dst_mac(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_DL_DST_SET +
+				"=(?:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+)\\:(\\p{XDigit}+))").matcher(actionToDecode);
+		if (n.matches()) {
+			MacAddress macaddr = MacAddress.of(get_mac_addr(n, actionToDecode, log));            
+			if (macaddr != null) {
+				OFActionSetDlDst.Builder ab = OFFactories.getFactory(version).actions().buildSetDlDst();
+				ab.setDlAddr(macaddr);
+				log.debug("action {}", ab.build());
+				return ab.build();
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetNwTos decode_set_tos_bits(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_NW_TOS_SET + "=((?:0x)?\\d+)").matcher(actionToDecode); 
+		if (n.matches()) {
+			if (n.group(1) != null) {
+				try {
+					byte tosbits = get_byte(n.group(1));
+					OFActionSetNwTos.Builder ab = OFFactories.getFactory(version).actions().buildSetNwTos();
+					ab.setNwTos(tosbits);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid dst-port in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFActionSetNwSrc decode_set_src_ip(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_NW_SRC_SET + "=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(actionToDecode);
+		if (n.matches()) {
+			IPv4Address ipaddr = IPv4Address.of(get_ip_addr(n, actionToDecode, log));
+			OFActionSetNwSrc.Builder ab = OFFactories.getFactory(version).actions().buildSetNwSrc();
+			ab.setNwAddr(ipaddr);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionSetNwDst decode_set_dst_ip(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_NW_DST_SET + "=(?:(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))").matcher(actionToDecode);
+		if (n.matches()) {
+			IPv4Address ipaddr = IPv4Address.of(get_ip_addr(n, actionToDecode, log));
+			OFActionSetNwDst.Builder ab = OFFactories.getFactory(version).actions().buildSetNwDst();
+			ab.setNwAddr(ipaddr);
+			log.debug("action {}", ab.build());
+			return ab.build();
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+	}
+
+	private static OFActionSetTpSrc decode_set_src_port(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_TP_SRC_SET + "=((?:0x)?\\d+)").matcher(actionToDecode); 
+		if (n.matches()) {
+			if (n.group(1) != null) {
+				try {
+					TransportPort portnum = TransportPort.of(get_short(n.group(1)));
+					OFActionSetTpSrc.Builder ab = OFFactories.getFactory(version).actions().buildSetTpSrc();
+					ab.setTpPort(portnum);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				} 
+				catch (NumberFormatException e) {
+					log.debug("Invalid src-port in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static OFAction decode_set_dst_port(String actionToDecode, OFVersion version, Logger log) {
+		Matcher n = Pattern.compile(STR_TP_DST_SET + "=((?:0x)?\\d+)").matcher(actionToDecode);
+		if (n.matches()) {
+			if (n.group(1) != null) {
+				try {
+					TransportPort portnum = TransportPort.of(get_short(n.group(1)));
+					OFActionSetTpDst.Builder ab = OFFactories.getFactory(version).actions().buildSetTpDst();
+					ab.setTpPort(portnum);
+					log.debug("action {}", ab.build());
+					return ab.build();
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid dst-port in: {} (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+		}
+		else {
+			log.debug("Invalid action: '{}'", actionToDecode);
+			return null;
+		}
+		return null;
+	}
+
+	private static byte[] get_mac_addr(Matcher n, String actionToDecode, Logger log) {
+		byte[] macaddr = new byte[6];     
+		for (int i=0; i<6; i++) {
+			if (n.group(i+1) != null) {
+				try {
+					macaddr[i] = get_byte("0x" + n.group(i+1));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid src-mac in: '{}' (error ignored)", actionToDecode);
+					return null;
+				}
+			}
+			else { 
+				log.debug("Invalid src-mac in: '{}' (null, error ignored)", actionToDecode);
+				return null;
+			}
+		}  
+		return macaddr;
+	}
+
+	private static int get_ip_addr(Matcher n, String actionToDecode, Logger log) {
+		int ipaddr = 0;
+		for (int i=0; i<4; i++) {
+			if (n.group(i+1) != null) {
+				try {
+					ipaddr = ipaddr<<8;
+					ipaddr = ipaddr | get_int(n.group(i+1));
+				}
+				catch (NumberFormatException e) {
+					log.debug("Invalid src-ip in: '{}' (error ignored)", actionToDecode);
+					return 0;
+				}
+			}
+			else {
+				log.debug("Invalid src-ip in: '{}' (null, error ignored)", actionToDecode);
+				return 0;
+			}
+		}
+		return ipaddr;
+	}
+
+	// Parse int as decimal, hex (start with 0x or #) or octal (starts with 0)
+	private static int get_int(String str) {
+		return Integer.decode(str);
+	}
+
+	// Parse short as decimal, hex (start with 0x or #) or octal (starts with 0)
+	private static short get_short(String str) {
+		return (short)(int)Integer.decode(str);
+	}
+
+	// Parse byte as decimal, hex (start with 0x or #) or octal (starts with 0)
+	private static byte get_byte(String str) {
+		return Integer.decode(str).byteValue();
+	}
+
+}
diff --git a/src/main/java/net/floodlightcontroller/util/FlowModUtils.java b/src/main/java/net/floodlightcontroller/util/FlowModUtils.java
index bd17cafdd84ee94a930bda41a8341279e82299bf..94ddeeb6eccd79bba2b8d3ddbcee8a952e338aea 100644
--- a/src/main/java/net/floodlightcontroller/util/FlowModUtils.java
+++ b/src/main/java/net/floodlightcontroller/util/FlowModUtils.java
@@ -13,10 +13,24 @@ import org.projectfloodlight.openflow.protocol.OFVersion;
  * Convert an OFFlowMod to a specific OFFlowMod-OFFlowModCommand.
  * These function as setCommand(OFFlowModCommand) methods for an OFFlowMod.
  * Used initially in the static flow pusher, but will likely find merit elsewhere.
+ * 
+ * Other useful FlowMod utility functions and constants are also included.
  *
  * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu>
  */
 public class FlowModUtils {
+	public static final int INFINITE_TIMEOUT = 0;
+	
+	public static final int PRIORITY_MAX = 32768;
+	public static final int PRIORITY_VERY_HIGH = 28672;
+	public static final int PRIORITY_HIGH = 24576;
+	public static final int PRIORITY_MED_HIGH = 20480;
+	public static final int PRIORITY_MED = 16384;
+	public static final int PRIORITY_MED_LOW = 12288;
+	public static final int PRIORITY_LOW = 8192;
+	public static final int PRIORITY_VERY_LOW = 4096;
+	public static final int PRIORITY_MIN = 0;
+	
 	public static OFFlowAdd toFlowAdd(OFFlowMod fm) {
 		OFVersion version = fm.getVersion();
 		OFFlowAdd.Builder b = OFFactories.getFactory(version).buildFlowAdd();
diff --git a/src/main/java/net/floodlightcontroller/util/MatchString.java b/src/main/java/net/floodlightcontroller/util/MatchString.java
deleted file mode 100644
index fb71e3cd1fb3cf6c108f37c94fe750e471df221f..0000000000000000000000000000000000000000
--- a/src/main/java/net/floodlightcontroller/util/MatchString.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package net.floodlightcontroller.util;
-
-import org.projectfloodlight.openflow.protocol.OFFactories;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.protocol.match.MatchField;
-import org.projectfloodlight.openflow.types.EthType;
-import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
-import org.projectfloodlight.openflow.types.IpDscp;
-import org.projectfloodlight.openflow.types.IpEcn;
-import org.projectfloodlight.openflow.types.IpProtocol;
-import org.projectfloodlight.openflow.types.MacAddress;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.OFVlanVidMatch;
-import org.projectfloodlight.openflow.types.TransportPort;
-import org.projectfloodlight.openflow.types.U8;
-import org.projectfloodlight.openflow.types.VlanPcp;
-
-
-/**
- * Represents an ofp_match structure
- * 
- * @author David Erickson (daviderickson@cs.stanford.edu)
- * @author Rob Sherwood (rob.sherwood@stanford.edu)
- * 
- */
-public class MatchString {
-    /* List of Strings for marshalling and unmarshalling to human readable forms */
-    final private static String STR_IN_PORT = "in_port";
-    final private static String STR_DL_DST = "dl_dst";
-    final private static String STR_DL_SRC = "dl_src";
-    final private static String STR_DL_TYPE = "dl_type";
-    final private static String STR_DL_VLAN = "dl_vlan";
-    final private static String STR_DL_VLAN_PCP = "dl_vpcp";
-    final private static String STR_NW_DST = "nw_dst";
-    final private static String STR_NW_SRC = "nw_src";
-    final private static String STR_NW_PROTO = "nw_proto";
-    final private static String STR_NW_TOS = "nw_tos";
-    final private static String STR_TP_DST = "tp_dst";
-    final private static String STR_TP_SRC = "tp_src";
-
-    /**
-     * Output a dpctl-styled string, i.e., only list the elements that are not
-     * wildcarded
-     * 
-     * A match-everything OFMatch outputs "OFMatch[]"
-     * 
-     * @return 
-     *         "OFMatch[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
-     */
-    /*public String toString(Match match) {
-        String str = "";
-
-        match
-        
-        // l1
-        if ((wildcards & OFPFW_IN_PORT) == 0)
-            str += "," + STR_IN_PORT + "=" + U16.f(this.inputPort);
-
-        // l2
-        if ((wildcards & OFPFW_DL_DST) == 0)
-            str += "," + STR_DL_DST + "="
-                    + match.);
-        if ((wildcards & OFPFW_DL_SRC) == 0)
-            str += "," + STR_DL_SRC + "="
-                    + HexString.toHexString(this.dataLayerSource);
-        if ((wildcards & OFPFW_DL_TYPE) == 0)
-            str += "," + STR_DL_TYPE + "=0x"
-                    + Integer.toHexString(U16.f(this.dataLayerType));
-        if ((wildcards & OFPFW_DL_VLAN) == 0)
-            str += "," + STR_DL_VLAN + "=0x"
-                    + Integer.toHexString(U16.f(this.dataLayerVirtualLan));
-        if ((wildcards & OFPFW_DL_VLAN_PCP) == 0)
-            str += ","
-                    + STR_DL_VLAN_PCP
-                    + "="
-                    + Integer.toHexString(U8
-                            .f(this.dataLayerVirtualLanPriorityCodePoint));
-
-        // l3
-        if (getNetworkDestinationMaskLen() > 0)
-            str += ","
-                    + STR_NW_DST
-                    + "="
-                    + cidrToString(networkDestination,
-                            getNetworkDestinationMaskLen());
-        if (getNetworkSourceMaskLen() > 0)
-            str += "," + STR_NW_SRC + "="
-                    + cidrToString(networkSource, getNetworkSourceMaskLen());
-        if ((wildcards & OFPFW_NW_PROTO) == 0)
-            str += "," + STR_NW_PROTO + "=" + U8.f(this.networkProtocol);
-        if ((wildcards & OFPFW_NW_TOS) == 0)
-            str += "," + STR_NW_TOS + "=" + U8.f(this.networkTypeOfService);
-
-        // l4
-        if ((wildcards & OFPFW_TP_DST) == 0)
-            str += "," + STR_TP_DST + "=" + U16.f(this.transportDestination);
-        if ((wildcards & OFPFW_TP_SRC) == 0)
-            str += "," + STR_TP_SRC + "=" + U16.f(this.transportSource);
-        if ((str.length() > 0) && (str.charAt(0) == ','))
-            str = str.substring(1); // trim the leading ","
-        // done
-        return "OFMatch[" + str + "]";
-    }*/
-
-    /**
-     * Based on the method from OFMatch in openflowj 1.0.
-     * Set this Match's parameters based on a comma-separated key=value pair
-     * dpctl-style string, e.g., from the output of OFMatch.toString() <br>
-     * <p>
-     * Supported keys/values include <br>
-     * <p>
-     * <TABLE border=1>
-     * <TR>
-     * <TD>KEY(s)
-     * <TD>VALUE
-     * </TR>
-     * <TR>
-     * <TD>"in_port","input_port"
-     * <TD>integer
-     * </TR>
-     * <TR>
-     * <TD>"dl_src","eth_src", "dl_dst","eth_dst"
-     * <TD>hex-string
-     * </TR>
-     * <TR>
-     * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp"
-     * <TD>integer
-     * </TR>
-     * <TR>
-     * <TD>"nw_src", "nw_dst", "ip_src", "ip_dst"
-     * <TD>CIDR-style netmask
-     * </TR>
-     * <TR>
-     * <TD>"tp_src","tp_dst"
-     * <TD>integer (max 64k)
-     * </TR>
-     * </TABLE>
-     * <p>
-     * The CIDR-style netmasks assume 32 netmask if none given, so:
-     * "128.8.128.118/32" is the same as "128.8.128.118"
-     * 
-     * @param match
-     *            a key=value comma separated string, e.g.
-     *            "in_port=5,ip_dst=192.168.0.0/16,tp_src=80"
-     * @throws IllegalArgumentException
-     *             on unexpected key or value
-     */
-
-    public static Match fromString(String match, OFVersion ofVersion) throws IllegalArgumentException {
-        if (match.equals("") || match.equalsIgnoreCase("any")
-                || match.equalsIgnoreCase("all") || match.equals("[]"))
-            match = "Match[]";
-        String[] tokens = match.split("[\\[,\\]]");
-        String[] values;
-        int initArg = 0;
-        if (tokens[0].equals("Match"))
-            initArg = 1;
-        
-        Match.Builder mb = OFFactories.getFactory(ofVersion).buildMatch();
-        
-        int i;
-        for (i = initArg; i < tokens.length; i++) {
-            values = tokens[i].split("=");
-            if (values.length != 2)
-                throw new IllegalArgumentException("Token " + tokens[i]
-                        + " does not have form 'key=value' parsing " + match);
-            values[0] = values[0].toLowerCase(); // try to make this case insens
-            if (values[0].equals(STR_IN_PORT) || values[0].equals("input_port")) {
-                mb.setExact(MatchField.IN_PORT, OFPort.of(Integer.valueOf(values[1])));
-            } else if (values[0].equals(STR_DL_DST) || values[0].equals("eth_dst")) {
-                mb.setExact(MatchField.ETH_DST, MacAddress.of(values[1]));
-            } else if (values[0].equals(STR_DL_SRC) || values[0].equals("eth_src")) {
-                mb.setExact(MatchField.ETH_SRC, MacAddress.of(values[1]));
-            } else if (values[0].equals(STR_DL_TYPE) || values[0].equals("eth_type")) {
-                if (values[1].startsWith("0x")) {
-                    mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(values[1].replaceFirst("0x", ""), 16)));
-                } else {
-                    mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(values[1])));
-                }
-            } else if (values[0].equals(STR_DL_VLAN)) {
-                if (values[1].contains("0x")) {
-                    mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(Integer.valueOf(values[1].replaceFirst("0x", ""), 16)));
-                } else {
-                    mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(Integer.valueOf(values[1])));
-                }
-            } else if (values[0].equals(STR_DL_VLAN_PCP)) {
-                mb.setExact(MatchField.VLAN_PCP, VlanPcp.of(U8.t(Short.valueOf(values[1]))));
-            } else if (values[0].equals(STR_NW_DST) || values[0].equals("ip_dst")) {
-                mb.setMasked(MatchField.IPV4_DST, IPv4AddressWithMask.of(values[1]));
-            } else if (values[0].equals(STR_NW_SRC) || values[0].equals("ip_src")) { 
-                mb.setMasked(MatchField.IPV4_SRC, IPv4AddressWithMask.of(values[1]));
-            } else if (values[0].equals(STR_NW_PROTO)) {
-                mb.setExact(MatchField.IP_PROTO, IpProtocol.of(Short.valueOf(values[1])));
-            } else if (values[0].equals(STR_NW_TOS)) {
-                mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(values[1]))));
-                mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(values[1]))));
-            } else if (values[0].equals(STR_TP_DST)) {
-            	if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.TCP)) {
-                    mb.setExact(MatchField.TCP_DST, TransportPort.of(Integer.valueOf(values[1])));
-            	} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.UDP)) {
-                    mb.setExact(MatchField.UDP_DST, TransportPort.of(Integer.valueOf(values[1])));
-            	} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.SCTP)) {
-                    mb.setExact(MatchField.SCTP_DST, TransportPort.of(Integer.valueOf(values[1])));
-            	}	
-            } else if (values[0].equals(STR_TP_SRC)) {
-            	if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.TCP)) {
-                    mb.setExact(MatchField.TCP_SRC, TransportPort.of(Integer.valueOf(values[1])));
-            	} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.UDP)) {
-                    mb.setExact(MatchField.UDP_SRC, TransportPort.of(Integer.valueOf(values[1])));
-            	} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.SCTP)) {
-                    mb.setExact(MatchField.SCTP_SRC, TransportPort.of(Integer.valueOf(values[1])));
-            	}	
-            } else {
-                throw new IllegalArgumentException("unknown token " + tokens[i] + " parsing " + match);
-            }
-        }
-        return mb.build();
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/net/floodlightcontroller/util/MatchUtils.java b/src/main/java/net/floodlightcontroller/util/MatchUtils.java
index 1d08b05d4174dde3002761801d74a331eebaa8d5..e10cf4a3fdf52b9466c9573f94ad06c49389f3e8 100644
--- a/src/main/java/net/floodlightcontroller/util/MatchUtils.java
+++ b/src/main/java/net/floodlightcontroller/util/MatchUtils.java
@@ -1,17 +1,82 @@
 package net.floodlightcontroller.util;
 
+import java.util.ArrayDeque;
+import java.util.Arrays;
 import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
 
 import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
+import org.projectfloodlight.openflow.types.ArpOpcode;
+import org.projectfloodlight.openflow.types.EthType;
+import org.projectfloodlight.openflow.types.ICMPv4Code;
+import org.projectfloodlight.openflow.types.ICMPv4Type;
+import org.projectfloodlight.openflow.types.IPv4Address;
+import org.projectfloodlight.openflow.types.IPv4AddressWithMask;
+import org.projectfloodlight.openflow.types.IpDscp;
+import org.projectfloodlight.openflow.types.IpEcn;
+import org.projectfloodlight.openflow.types.IpProtocol;
+import org.projectfloodlight.openflow.types.MacAddress;
+import org.projectfloodlight.openflow.types.OFMetadata;
+import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.TransportPort;
+import org.projectfloodlight.openflow.types.U32;
+import org.projectfloodlight.openflow.types.U8;
+import org.projectfloodlight.openflow.types.VlanPcp;
 
 /**
  * Match helper functions. Use with any OpenFlowJ-Loxi Match.
+ * 
+ * Includes string methods adopted from OpenFlowJ for OpenFlow 1.0.
  *
  * @author Ryan Izard <ryan.izard@bigswitch.com, rizard@g.clemson.edu>
+ * @author David Erickson (daviderickson@cs.stanford.edu)
+ * @author Rob Sherwood (rob.sherwood@stanford.edu)
  */
 public class MatchUtils {
+	/* List of Strings for marshalling and unmarshalling to human readable forms.
+	 * Classes that convert from Match and String should reference these fields for a
+	 * common string representation throughout the controller. The StaticFlowEntryPusher
+	 * is one such example that references these strings.
+	 */
+	public static final String STR_IN_PORT = "ingress_port";
+
+	public static final String STR_DL_DST = "dl_dst";
+	public static final String STR_DL_SRC = "dl_src";
+	public static final String STR_DL_TYPE = "dl_type";
+	public static final String STR_DL_VLAN = "dl_vlan";
+	public static final String STR_DL_VLAN_PCP = "dl_vpcp";
+
+	public static final String STR_NW_DST = "nw_dst";
+	public static final String STR_NW_SRC = "nw_src";
+	public static final String STR_NW_PROTO = "nw_proto";
+	public static final String STR_NW_TOS = "nw_tos";
+
+	public static final String STR_TP_DST = "tp_dst";
+	public static final String STR_TP_SRC = "tp_src";
+
+	public static final String STR_ICMP_TYPE = "icmp_type";
+	public static final String STR_ICMP_CODE = "icmp_code";
+
+	public static final String STR_ARP_OPCODE = "arp_opcode";
+	public static final String STR_ARP_SHA = "arp_sha";
+	public static final String STR_ARP_DHA = "arp_dha";
+	public static final String STR_ARP_SPA = "arp_spa";
+	public static final String STR_ARP_DPA = "arp_dpa";
+
+	public static final String STR_MPLS_LABEL = "mpls_label";
+	public static final String STR_MPLS_TC = "mpls_tc";
+	public static final String STR_MPLS_BOS = "mpls_bos";
+
+	public static final String STR_METADATA = "metadata";
+	public static final String STR_TUNNEL_ID = "tunnel_id";
+
+	public static final String STR_PBB_ISID = "pbb_isid";	
+
 	/**
 	 * Create a point-to-point match for two devices at the IP layer.
 	 * Takes an existing match (e.g. from a PACKET_IN), and masks all
@@ -98,7 +163,7 @@ public class MatchUtils {
 		}
 		return mb;
 	}
-	
+
 	/**
 	 * Create a Match builder the same OF version as Match m. The returned builder
 	 * will not retain any MatchField information from Match m and will
@@ -112,7 +177,7 @@ public class MatchUtils {
 	public static Match.Builder createForgetfulBuilder(Match m) {
 		return OFFactories.getFactory(m.getVersion()).buildMatch();
 	}
-	
+
 	/**
 	 * Create a duplicate Match object from Match m.
 	 * 
@@ -122,4 +187,250 @@ public class MatchUtils {
 	public static Match createCopy(Match m) {
 		return m.createBuilder().build(); // will use parent MatchFields to produce the new Match only if the builder is never modified
 	}
+
+	/**
+	 * TODO @Ryan NOT IMPLEMENTED! Returns empty string right now.
+	 * Output a dpctl-styled string, i.e., only list the elements that are not wildcarded.
+	 * 
+	 * A match-everything Match outputs "Match[]"
+	 * 
+	 * @return "Match[dl_src:00:20:01:11:22:33,nw_src:192.168.0.0/24,tp_dst:80]"
+	 */
+	public static String toString(Match match) {
+		/*String str = "";
+
+	        match
+
+	        // l1
+	        if ((wildcards & OFPFW_IN_PORT) == 0)
+	            str += "," + STR_IN_PORT + "=" + U16.f(this.inputPort);
+
+	        // l2
+	        if ((wildcards & OFPFW_DL_DST) == 0)
+	            str += "," + STR_DL_DST + "="
+	                    + match.);
+	        if ((wildcards & OFPFW_DL_SRC) == 0)
+	            str += "," + STR_DL_SRC + "="
+	                    + HexString.toHexString(this.dataLayerSource);
+	        if ((wildcards & OFPFW_DL_TYPE) == 0)
+	            str += "," + STR_DL_TYPE + "=0x"
+	                    + Integer.toHexString(U16.f(this.dataLayerType));
+	        if ((wildcards & OFPFW_DL_VLAN) == 0)
+	            str += "," + STR_DL_VLAN + "=0x"
+	                    + Integer.toHexString(U16.f(this.dataLayerVirtualLan));
+	        if ((wildcards & OFPFW_DL_VLAN_PCP) == 0)
+	            str += ","
+	                    + STR_DL_VLAN_PCP
+	                    + "="
+	                    + Integer.toHexString(U8
+	                            .f(this.dataLayerVirtualLanPriorityCodePoint));
+
+	        // l3
+	        if (getNetworkDestinationMaskLen() > 0)
+	            str += ","
+	                    + STR_NW_DST
+	                    + "="
+	                    + cidrToString(networkDestination,
+	                            getNetworkDestinationMaskLen());
+	        if (getNetworkSourceMaskLen() > 0)
+	            str += "," + STR_NW_SRC + "="
+	                    + cidrToString(networkSource, getNetworkSourceMaskLen());
+	        if ((wildcards & OFPFW_NW_PROTO) == 0)
+	            str += "," + STR_NW_PROTO + "=" + U8.f(this.networkProtocol);
+	        if ((wildcards & OFPFW_NW_TOS) == 0)
+	            str += "," + STR_NW_TOS + "=" + U8.f(this.networkTypeOfService);
+
+	        // l4
+	        if ((wildcards & OFPFW_TP_DST) == 0)
+	            str += "," + STR_TP_DST + "=" + U16.f(this.transportDestination);
+	        if ((wildcards & OFPFW_TP_SRC) == 0)
+	            str += "," + STR_TP_SRC + "=" + U16.f(this.transportSource);
+	        if ((str.length() > 0) && (str.charAt(0) == ','))
+	            str = str.substring(1); // trim the leading ","
+	        // done
+	        return "OFMatch[" + str + "]"; */
+		return "";
+	}
+
+	/**
+	 * Based on the method from OFMatch in openflowj 1.0.
+	 * Set this Match's parameters based on a comma-separated key=value pair
+	 * dpctl-style string, e.g., from the output of OFMatch.toString() <br>
+	 * <p>
+	 * Supported keys/values include <br>
+	 * <p>
+	 * <TABLE border=1>
+	 * <TR>
+	 * <TD>KEY(s)
+	 * <TD>VALUE
+	 * </TR>
+	 * <TR>
+	 * <TD>"in_port","input_port"
+	 * <TD>integer
+	 * </TR>
+	 * <TR>
+	 * <TD>"dl_src", "dl_dst"
+	 * <TD>hex-string
+	 * </TR>
+	 * <TR>
+	 * <TD>"dl_type", "dl_vlan", "dl_vlan_pcp"
+	 * <TD>integer
+	 * </TR>
+	 * <TR>
+	 * <TD>"nw_src", "nw_dst"
+	 * <TD>CIDR-style netmask
+	 * </TR>
+	 * <TR>
+	 * <TD>"tp_src","tp_dst"
+	 * <TD>integer (max 64k)
+	 * </TR>
+	 * </TABLE>
+	 * <p>
+	 * The CIDR-style netmasks assume 32 netmask if none given, so:
+	 * "128.8.128.118/32" is the same as "128.8.128.118"
+	 * 
+	 * @param match
+	 *            a key=value comma separated string, e.g.
+	 *            "in_port=5,nw_dst=192.168.0.0/16,tp_src=80"
+	 * @throws IllegalArgumentException
+	 *             on unexpected key or value
+	 */
+	public static Match fromString(String match, OFVersion ofVersion) throws IllegalArgumentException {
+		if (match.equals("") || match.equalsIgnoreCase("any") || match.equalsIgnoreCase("all") || match.equals("[]")) {
+			match = "Match[]";
+		}
+		
+		// Split into pairs of key=value
+		String[] tokens = match.split("[\\[,\\]]");
+		int initArg = 0;
+		if (tokens[0].equals("Match")) {
+			initArg = 1;
+		}
+		
+		// Split up key=value pairs into [key, value], and insert into linked list
+		int i;
+		String[] tmp;
+		ArrayDeque<String[]> llValues = new ArrayDeque<String[]>();
+		for (i = initArg; i < tokens.length; i++) {
+			tmp = tokens[i].split("=");
+			if (tmp.length != 2) {
+				throw new IllegalArgumentException("Token " + tokens[i] + " does not have form 'key=value' parsing " + match);
+			}
+			tmp[0] = tmp[0].toLowerCase(); // try to make key parsing case insensitive
+			llValues.add(tmp); // llValues contains [key, value] pairs. Create a queue of pairs to process.
+		}	
+
+		Match.Builder mb = OFFactories.getFactory(ofVersion).buildMatch();
+
+		while (!llValues.isEmpty()) {
+			IpProtocol ipProto; // used to prevent lots of match.get()'s for detecting transport protocol
+			String[] key_value = llValues.pollFirst(); // pop off the first element; this completely removes it from the queue.
+			switch (key_value[0]) {
+			case STR_IN_PORT:
+				mb.setExact(MatchField.IN_PORT, OFPort.of(Integer.valueOf(key_value[1])));
+				break;
+			case STR_DL_DST:
+				mb.setExact(MatchField.ETH_DST, MacAddress.of(key_value[1]));
+				break;
+			case STR_DL_SRC:
+				mb.setExact(MatchField.ETH_SRC, MacAddress.of(key_value[1]));
+				break;
+			case STR_DL_TYPE:
+				if (key_value[1].startsWith("0x")) {
+					mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(key_value[1].replaceFirst("0x", ""), 16)));
+				} else {
+					mb.setExact(MatchField.ETH_TYPE, EthType.of(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_DL_VLAN:
+				if (key_value[1].contains("0x")) {
+					mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(Integer.valueOf(key_value[1].replaceFirst("0x", ""), 16)));
+				} else {
+					mb.setExact(MatchField.VLAN_VID, OFVlanVidMatch.ofVlan(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_DL_VLAN_PCP:
+				mb.setExact(MatchField.VLAN_PCP, VlanPcp.of(U8.t(Short.valueOf(key_value[1]))));
+				break;
+			case STR_NW_DST:
+				mb.setMasked(MatchField.IPV4_DST, IPv4AddressWithMask.of(key_value[1]));
+				break;
+			case STR_NW_SRC:
+				mb.setMasked(MatchField.IPV4_SRC, IPv4AddressWithMask.of(key_value[1]));
+				break;
+			case STR_NW_PROTO:
+				mb.setExact(MatchField.IP_PROTO, IpProtocol.of(Short.valueOf(key_value[1])));
+				break;
+			case STR_NW_TOS:
+				mb.setExact(MatchField.IP_ECN, IpEcn.of(U8.t(Short.valueOf(key_value[1]))));
+				mb.setExact(MatchField.IP_DSCP, IpDscp.of(U8.t(Short.valueOf(key_value[1]))));
+				break;
+			case STR_TP_DST:
+				// if we don't know the transport protocol yet, postpone parsing this [key, value] pair until we know. Put it at the back of the queue.
+				if ((ipProto = mb.get(MatchField.IP_PROTO)) == null) {
+					llValues.add(key_value); // place it back if we can't proceed yet
+				} else if (ipProto.equals(IpProtocol.TCP)) {
+					mb.setExact(MatchField.TCP_DST, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (ipProto.equals(IpProtocol.UDP)) {
+					mb.setExact(MatchField.UDP_DST, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (ipProto.equals(IpProtocol.SCTP)) {
+					mb.setExact(MatchField.SCTP_DST, TransportPort.of(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_TP_SRC:
+				if ((ipProto = mb.get(MatchField.IP_PROTO)) == null) {
+					llValues.add(key_value); // place it back if we can't proceed yet
+				} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.TCP)) {
+					mb.setExact(MatchField.TCP_SRC, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.UDP)) {
+					mb.setExact(MatchField.UDP_SRC, TransportPort.of(Integer.valueOf(key_value[1])));
+				} else if (mb.get(MatchField.IP_PROTO).equals(IpProtocol.SCTP)) {
+					mb.setExact(MatchField.SCTP_SRC, TransportPort.of(Integer.valueOf(key_value[1])));
+				}
+				break;
+			case STR_ICMP_TYPE:
+				mb.setExact(MatchField.ICMPV4_TYPE, ICMPv4Type.of(Short.parseShort(key_value[1])));
+				break;
+			case STR_ICMP_CODE:
+				mb.setExact(MatchField.ICMPV4_CODE, ICMPv4Code.of(Short.parseShort(key_value[1])));
+				break;
+			case STR_ARP_OPCODE:
+				mb.setExact(MatchField.ARP_OP, ArpOpcode.of(Integer.parseInt(key_value[1])));
+				break;
+			case STR_ARP_SHA:
+				mb.setExact(MatchField.ARP_SHA, MacAddress.of(key_value[1]));
+				break;
+			case STR_ARP_DHA:
+				mb.setExact(MatchField.ARP_THA, MacAddress.of(key_value[1]));
+				break;
+			case STR_ARP_SPA:
+				mb.setExact(MatchField.ARP_SPA, IPv4Address.of(key_value[1]));
+				break;
+			case STR_ARP_DPA:
+				mb.setExact(MatchField.ARP_TPA, IPv4Address.of(key_value[1]));
+				break;
+			case STR_MPLS_LABEL:
+				mb.setExact(MatchField.MPLS_LABEL, U32.of(Long.parseLong(key_value[1])));
+				break;
+			case STR_MPLS_TC:
+				mb.setExact(MatchField.MPLS_TC, U8.of(Short.parseShort(key_value[1])));
+				break;
+			case STR_MPLS_BOS:
+				//no-op. Not implemented.
+				break;
+			case STR_METADATA:
+				mb.setExact(MatchField.METADATA, OFMetadata.ofRaw(Long.parseLong(key_value[1])));
+				break;
+			case STR_TUNNEL_ID:
+				//no-op. Not implemented.
+				break;
+			case STR_PBB_ISID:
+				//no-op. Not implemented.
+				break;
+			default:
+				throw new IllegalArgumentException("unknown token " + key_value + " parsing " + match);
+			} 
+		}
+		return mb.build();
+	}
 }