Merge remote-tracking branch 'origin/master'
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
index 0300079..c3fd6ed 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
@@ -201,7 +201,7 @@
         @Override
         public TrafficTreatment build() {
 
-            //If we are dropping should we just return an emptry list?
+            //If we are dropping should we just return an empty list?
             List<Instruction> instructions = new LinkedList<Instruction>();
             instructions.addAll(modifications);
             instructions.addAll(groups);
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
index e04d87c..2a91b5b 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowEntryBuilder.java
@@ -33,7 +33,7 @@
 import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanPcp;
 import org.projectfloodlight.openflow.protocol.action.OFActionSetVlanVid;
 import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstructionWriteActions;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.protocol.oxm.OFOxmOchSigidBasic;
@@ -104,8 +104,8 @@
             case OF_13:
                 List<OFInstruction> ins = entry.getInstructions();
                 for (OFInstruction in : ins) {
-                    if (in.getType().equals(OFInstructionType.APPLY_ACTIONS)) {
-                        OFInstructionApplyActions apply = (OFInstructionApplyActions) in;
+                    if (in.getType().equals(OFInstructionType.WRITE_ACTIONS)) {
+                        OFInstructionWriteActions apply = (OFInstructionWriteActions) in;
                         return apply.getActions();
                     }
                 }
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
index e1fde8a..e0fb7d9 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilder.java
@@ -2,14 +2,8 @@
 
 import static org.slf4j.LoggerFactory.getLogger;
 
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.onlab.onos.net.flow.FlowId;
 import org.onlab.onos.net.flow.FlowRule;
 import org.onlab.onos.net.flow.TrafficSelector;
-import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.flow.criteria.Criteria.EthCriterion;
 import org.onlab.onos.net.flow.criteria.Criteria.EthTypeCriterion;
 import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
@@ -20,22 +14,10 @@
 import org.onlab.onos.net.flow.criteria.Criteria.VlanIdCriterion;
 import org.onlab.onos.net.flow.criteria.Criteria.VlanPcpCriterion;
 import org.onlab.onos.net.flow.criteria.Criterion;
-import org.onlab.onos.net.flow.instructions.Instruction;
-import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
-import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
-import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
-import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
-import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
-import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
 import org.projectfloodlight.openflow.protocol.OFFlowDelete;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
 import org.projectfloodlight.openflow.protocol.match.Match;
 import org.projectfloodlight.openflow.protocol.match.MatchField;
 import org.projectfloodlight.openflow.types.CircuitSignalID;
@@ -44,181 +26,82 @@
 import org.projectfloodlight.openflow.types.IpProtocol;
 import org.projectfloodlight.openflow.types.MacAddress;
 import org.projectfloodlight.openflow.types.Masked;
-import org.projectfloodlight.openflow.types.OFBufferId;
 import org.projectfloodlight.openflow.types.OFPort;
 import org.projectfloodlight.openflow.types.OFVlanVidMatch;
 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.slf4j.Logger;
 
-
-public class FlowModBuilder {
+/**
+ * Builder for OpenFlow flow mods based on FlowRules.
+ */
+public abstract class FlowModBuilder {
 
     private final Logger log = getLogger(getClass());
 
     private final OFFactory factory;
-    private final TrafficTreatment treatment;
+    private final FlowRule flowRule;
     private final TrafficSelector selector;
 
-    private final int priority;
+    /**
+     * Creates a new flow mod builder.
+     *
+     * @param flowRule the flow rule to transform into a flow mod
+     * @param factory the OpenFlow factory to use to build the flow mod
+     * @return the new flow mod builder
+     */
+    public static FlowModBuilder builder(FlowRule flowRule, OFFactory factory) {
+        switch (factory.getVersion()) {
+        case OF_10:
+            return new FlowModBuilderVer10(flowRule, factory);
+        case OF_13:
+            return new FlowModBuilderVer13(flowRule, factory);
+        default:
+            throw new UnsupportedOperationException(
+                    "No flow mod builder for protocol version " + factory.getVersion());
+        }
+    }
 
-    private final FlowId cookie;
-
-
-
-    public FlowModBuilder(FlowRule flowRule, OFFactory factory) {
+    /**
+     * Constructs a flow mod builder.
+     *
+     * @param flowRule the flow rule to transform into a flow mod
+     * @param factory the OpenFlow factory to use to build the flow mod
+     */
+    protected FlowModBuilder(FlowRule flowRule, OFFactory factory) {
         this.factory = factory;
-        this.treatment = flowRule.treatment();
+        this.flowRule = flowRule;
         this.selector = flowRule.selector();
-        this.priority = flowRule.priority();
-        this.cookie = flowRule.id();
     }
 
-    public OFFlowAdd buildFlowAdd() {
-        Match match = buildMatch();
-        List<OFAction> actions = buildActions();
+    /**
+     * Builds an ADD flow mod.
+     *
+     * @return the flow mod
+     */
+    public abstract OFFlowAdd buildFlowAdd();
 
-        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
-        OFFlowAdd fm = factory.buildFlowAdd()
-                .setXid(cookie.value())
-                .setCookie(U64.of(cookie.value()))
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setActions(actions)
-                .setMatch(match)
-                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
-                .setPriority(priority)
-                .build();
+    /**
+     * Builds a MODIFY flow mod.
+     *
+     * @return the flow mod
+     */
+    public abstract OFFlowMod buildFlowMod();
 
-        return fm;
+    /**
+     * Builds a DELETE flow mod.
+     *
+     * @return the flow mod
+     */
+    public abstract OFFlowDelete buildFlowDel();
 
-    }
-
-    public OFFlowMod buildFlowMod() {
-        Match match = buildMatch();
-        List<OFAction> actions = buildActions();
-
-        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
-        OFFlowMod fm = factory.buildFlowModify()
-                .setXid(cookie.value())
-                .setCookie(U64.of(cookie.value()))
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setActions(actions)
-                .setMatch(match)
-                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
-                .setPriority(priority)
-                .build();
-
-        return fm;
-
-    }
-
-    public OFFlowDelete buildFlowDel() {
-        Match match = buildMatch();
-        List<OFAction> actions = buildActions();
-
-        OFFlowDelete fm = factory.buildFlowDelete()
-                .setXid(cookie.value())
-                .setCookie(U64.of(cookie.value()))
-                .setBufferId(OFBufferId.NO_BUFFER)
-                .setActions(actions)
-                .setMatch(match)
-                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
-                .setPriority(priority)
-                .build();
-
-        return fm;
-    }
-
-    private List<OFAction> buildActions() {
-        List<OFAction> acts = new LinkedList<>();
-        if (treatment == null) {
-            return acts;
-        }
-        for (Instruction i : treatment.instructions()) {
-            switch (i.type()) {
-            case DROP:
-                log.warn("Saw drop action; assigning drop action");
-                return new LinkedList<>();
-            case L0MODIFICATION:
-                acts.add(buildL0Modification(i));
-                break;
-            case L2MODIFICATION:
-                acts.add(buildL2Modification(i));
-                break;
-            case L3MODIFICATION:
-                acts.add(buildL3Modification(i));
-                break;
-            case OUTPUT:
-                OutputInstruction out = (OutputInstruction) i;
-                acts.add(factory.actions().buildOutput().setPort(
-                        OFPort.of((int) out.port().toLong())).build());
-                break;
-            case GROUP:
-            default:
-                log.warn("Instruction type {} not yet implemented.", i.type());
-            }
-        }
-
-        return acts;
-    }
-
-    private OFAction buildL0Modification(Instruction i) {
-        L0ModificationInstruction l0m = (L0ModificationInstruction) i;
-        switch (l0m.subtype()) {
-        case LAMBDA:
-            ModLambdaInstruction ml = (ModLambdaInstruction) i;
-            return factory.actions().circuit(factory.oxms().ochSigidBasic(
-                    new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
-        default:
-            log.warn("Unimplemented action type {}.", l0m.subtype());
-            break;
-        }
-        return null;
-    }
-
-    private OFAction buildL3Modification(Instruction i) {
-        L3ModificationInstruction l3m = (L3ModificationInstruction) i;
-        ModIPInstruction ip;
-        switch (l3m.subtype()) {
-        case IP_DST:
-            ip = (ModIPInstruction) i;
-            return factory.actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
-        case IP_SRC:
-            ip = (ModIPInstruction) i;
-            return factory.actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
-        default:
-            log.warn("Unimplemented action type {}.", l3m.subtype());
-            break;
-        }
-        return null;
-    }
-
-    private OFAction buildL2Modification(Instruction i) {
-        L2ModificationInstruction l2m = (L2ModificationInstruction) i;
-        ModEtherInstruction eth;
-        switch (l2m.subtype()) {
-        case ETH_DST:
-            eth = (ModEtherInstruction) l2m;
-            return factory.actions().setDlDst(MacAddress.of(eth.mac().toLong()));
-        case ETH_SRC:
-            eth = (ModEtherInstruction) l2m;
-            return factory.actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
-        case VLAN_ID:
-            ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
-            return factory.actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId.toShort()));
-        case VLAN_PCP:
-            ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
-            return factory.actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
-        default:
-            log.warn("Unimplemented action type {}.", l2m.subtype());
-            break;
-        }
-        return null;
-    }
-
-    private Match buildMatch() {
+    /**
+     * Builds the match for the flow mod.
+     *
+     * @return the match
+     */
+    protected Match buildMatch() {
         Match.Builder mBuilder = factory.buildMatch();
         EthCriterion eth;
         IPCriterion ip;
@@ -323,6 +206,22 @@
         return mBuilder.build();
     }
 
+    /**
+     * Returns the flow rule for this builder.
+     *
+     * @return the flow rule
+     */
+    protected FlowRule flowRule() {
+        return flowRule;
+    }
 
+    /**
+     * Returns the factory used for building OpenFlow constructs.
+     *
+     * @return the factory
+     */
+    protected OFFactory factory() {
+        return factory;
+    }
 
 }
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer10.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer10.java
new file mode 100644
index 0000000..fd54131
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -0,0 +1,191 @@
+package org.onlab.onos.provider.of.flow.impl;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.instructions.Instruction;
+import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+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.U64;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.projectfloodlight.openflow.types.VlanVid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Flow mod builder for OpenFlow 1.0.
+ */
+public class FlowModBuilderVer10 extends FlowModBuilder {
+
+    private static final Logger log = LoggerFactory.getLogger(FlowModBuilderVer10.class);
+
+    private final TrafficTreatment treatment;
+
+    /**
+     * Constructor for a flow mod builder for OpenFlow 1.0.
+     *
+     * @param flowRule the flow rule to transform into a flow mod
+     * @param factory the OpenFlow factory to use to build the flow mod
+     */
+    protected FlowModBuilderVer10(FlowRule flowRule, OFFactory factory) {
+        super(flowRule, factory);
+
+        this.treatment = flowRule.treatment();
+    }
+
+    @Override
+    public OFFlowAdd buildFlowAdd() {
+        Match match = buildMatch();
+        List<OFAction> actions = buildActions();
+
+        long cookie = flowRule().id().value();
+
+        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+        OFFlowAdd fm = factory().buildFlowAdd()
+                .setXid(cookie)
+                .setCookie(U64.of(cookie))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setActions(actions)
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setPriority(flowRule().priority())
+                .build();
+
+        return fm;
+    }
+
+    @Override
+    public OFFlowMod buildFlowMod() {
+        Match match = buildMatch();
+        List<OFAction> actions = buildActions();
+
+        long cookie = flowRule().id().value();
+
+        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+        OFFlowMod fm = factory().buildFlowModify()
+                .setXid(cookie)
+                .setCookie(U64.of(cookie))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setActions(actions)
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setPriority(flowRule().priority())
+                .build();
+
+        return fm;
+    }
+
+    @Override
+    public OFFlowDelete buildFlowDel() {
+        Match match = buildMatch();
+        List<OFAction> actions = buildActions();
+
+        long cookie = flowRule().id().value();
+
+        OFFlowDelete fm = factory().buildFlowDelete()
+                .setXid(cookie)
+                .setCookie(U64.of(cookie))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setActions(actions)
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setPriority(flowRule().priority())
+                .build();
+
+        return fm;
+    }
+
+    private List<OFAction> buildActions() {
+        List<OFAction> acts = new LinkedList<>();
+        if (treatment == null) {
+            return acts;
+        }
+        for (Instruction i : treatment.instructions()) {
+            switch (i.type()) {
+            case DROP:
+                log.warn("Saw drop action; assigning drop action");
+                return new LinkedList<>();
+            case L2MODIFICATION:
+                acts.add(buildL2Modification(i));
+                break;
+            case L3MODIFICATION:
+                acts.add(buildL3Modification(i));
+                break;
+            case OUTPUT:
+                OutputInstruction out = (OutputInstruction) i;
+                acts.add(factory().actions().buildOutput().setPort(
+                        OFPort.of((int) out.port().toLong())).build());
+                break;
+            case L0MODIFICATION:
+            case GROUP:
+                log.warn("Instruction type {} not supported with protocol version {}",
+                        i.type(), factory().getVersion());
+                break;
+            default:
+                log.warn("Instruction type {} not yet implemented.", i.type());
+            }
+        }
+
+        return acts;
+    }
+
+    private OFAction buildL3Modification(Instruction i) {
+        L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+        ModIPInstruction ip;
+        switch (l3m.subtype()) {
+        case IP_DST:
+            ip = (ModIPInstruction) i;
+            return factory().actions().setNwDst(IPv4Address.of(ip.ip().toInt()));
+        case IP_SRC:
+            ip = (ModIPInstruction) i;
+            return factory().actions().setNwSrc(IPv4Address.of(ip.ip().toInt()));
+        default:
+            log.warn("Unimplemented action type {}.", l3m.subtype());
+            break;
+        }
+        return null;
+    }
+
+    private OFAction buildL2Modification(Instruction i) {
+        L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+        ModEtherInstruction eth;
+        switch (l2m.subtype()) {
+        case ETH_DST:
+            eth = (ModEtherInstruction) l2m;
+            return factory().actions().setDlDst(MacAddress.of(eth.mac().toLong()));
+        case ETH_SRC:
+            eth = (ModEtherInstruction) l2m;
+            return factory().actions().setDlSrc(MacAddress.of(eth.mac().toLong()));
+        case VLAN_ID:
+            ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+            return factory().actions().setVlanVid(VlanVid.ofVlan(vlanId.vlanId.toShort()));
+        case VLAN_PCP:
+            ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+            return factory().actions().setVlanPcp(VlanPcp.of(vlanPcp.vlanPcp()));
+        default:
+            log.warn("Unimplemented action type {}.", l2m.subtype());
+            break;
+        }
+        return null;
+    }
+
+}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer13.java
new file mode 100644
index 0000000..35e99e1
--- /dev/null
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -0,0 +1,226 @@
+package org.onlab.onos.provider.of.flow.impl;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.onlab.onos.net.flow.FlowRule;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.instructions.Instruction;
+import org.onlab.onos.net.flow.instructions.Instructions.OutputInstruction;
+import org.onlab.onos.net.flow.instructions.L0ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onlab.onos.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction;
+import org.onlab.onos.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFFlowAdd;
+import org.projectfloodlight.openflow.protocol.OFFlowDelete;
+import org.projectfloodlight.openflow.protocol.OFFlowMod;
+import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
+import org.projectfloodlight.openflow.protocol.match.Match;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.types.CircuitSignalID;
+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.OFVlanVidMatch;
+import org.projectfloodlight.openflow.types.U64;
+import org.projectfloodlight.openflow.types.VlanPcp;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Flow mod builder for OpenFlow 1.3+.
+ */
+public class FlowModBuilderVer13 extends FlowModBuilder {
+
+    private static final Logger log = LoggerFactory.getLogger(FlowModBuilderVer10.class);
+
+    private final TrafficTreatment treatment;
+
+    /**
+     * Constructor for a flow mod builder for OpenFlow 1.3.
+     *
+     * @param flowRule the flow rule to transform into a flow mod
+     * @param factory the OpenFlow factory to use to build the flow mod
+     */
+    protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory) {
+        super(flowRule, factory);
+
+        this.treatment = flowRule.treatment();
+    }
+
+    @Override
+    public OFFlowAdd buildFlowAdd() {
+        Match match = buildMatch();
+        OFInstruction writeActions =
+                factory().instructions().writeActions(buildActions());
+
+        long cookie = flowRule().id().value();
+
+        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+        OFFlowAdd fm = factory().buildFlowAdd()
+                .setXid(cookie)
+                .setCookie(U64.of(cookie))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setInstructions(Collections.singletonList(writeActions))
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setPriority(flowRule().priority())
+                .build();
+
+        return fm;
+    }
+
+    @Override
+    public OFFlowMod buildFlowMod() {
+        Match match = buildMatch();
+        OFInstruction writeActions =
+                factory().instructions().writeActions(buildActions());
+
+        long cookie = flowRule().id().value();
+
+        //TODO: what to do without bufferid? do we assume that there will be a pktout as well?
+        OFFlowMod fm = factory().buildFlowModify()
+                .setXid(cookie)
+                .setCookie(U64.of(cookie))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setInstructions(Collections.singletonList(writeActions))
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setPriority(flowRule().priority())
+                .build();
+
+        return fm;
+    }
+
+    @Override
+    public OFFlowDelete buildFlowDel() {
+        Match match = buildMatch();
+        OFInstruction writeActions =
+                factory().instructions().writeActions(buildActions());
+
+        long cookie = flowRule().id().value();
+
+        OFFlowDelete fm = factory().buildFlowDelete()
+                .setXid(cookie)
+                .setCookie(U64.of(cookie))
+                .setBufferId(OFBufferId.NO_BUFFER)
+                .setInstructions(Collections.singletonList(writeActions))
+                .setMatch(match)
+                .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
+                .setPriority(flowRule().priority())
+                .build();
+
+        return fm;
+    }
+
+    private List<OFAction> buildActions() {
+        List<OFAction> actions = new LinkedList<>();
+        if (treatment == null) {
+            return actions;
+        }
+        for (Instruction i : treatment.instructions()) {
+            switch (i.type()) {
+            case DROP:
+                log.warn("Saw drop action; assigning drop action");
+                return new LinkedList<>();
+            case L0MODIFICATION:
+                actions.add(buildL0Modification(i));
+                break;
+            case L2MODIFICATION:
+                actions.add(buildL2Modification(i));
+                break;
+            case L3MODIFICATION:
+                actions.add(buildL3Modification(i));
+                break;
+            case OUTPUT:
+                OutputInstruction out = (OutputInstruction) i;
+                actions.add(factory().actions().buildOutput().setPort(
+                        OFPort.of((int) out.port().toLong())).build());
+                break;
+            case GROUP:
+            default:
+                log.warn("Instruction type {} not yet implemented.", i.type());
+            }
+        }
+
+        return actions;
+    }
+
+    private OFAction buildL0Modification(Instruction i) {
+        L0ModificationInstruction l0m = (L0ModificationInstruction) i;
+        switch (l0m.subtype()) {
+        case LAMBDA:
+            ModLambdaInstruction ml = (ModLambdaInstruction) i;
+            return factory().actions().circuit(factory().oxms().ochSigidBasic(
+                    new CircuitSignalID((byte) 1, (byte) 2, ml.lambda(), (short) 1)));
+        default:
+            log.warn("Unimplemented action type {}.", l0m.subtype());
+            break;
+        }
+        return null;
+    }
+
+    private OFAction buildL2Modification(Instruction i) {
+        L2ModificationInstruction l2m = (L2ModificationInstruction) i;
+        ModEtherInstruction eth;
+        OFOxm<?> oxm = null;
+        switch (l2m.subtype()) {
+        case ETH_DST:
+            eth = (ModEtherInstruction) l2m;
+            oxm = factory().oxms().ethDst(MacAddress.of(eth.mac().toLong()));
+            break;
+        case ETH_SRC:
+            eth = (ModEtherInstruction) l2m;
+            oxm = factory().oxms().ethSrc(MacAddress.of(eth.mac().toLong()));
+            break;
+        case VLAN_ID:
+            ModVlanIdInstruction vlanId = (ModVlanIdInstruction) l2m;
+            oxm = factory().oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanId.vlanId.toShort()));
+            break;
+        case VLAN_PCP:
+            ModVlanPcpInstruction vlanPcp = (ModVlanPcpInstruction) l2m;
+            oxm = factory().oxms().vlanPcp(VlanPcp.of(vlanPcp.vlanPcp));
+            break;
+        default:
+            log.warn("Unimplemented action type {}.", l2m.subtype());
+            break;
+        }
+
+        if (oxm != null) {
+            return factory().actions().buildSetField().setField(oxm).build();
+        }
+        return null;
+    }
+
+    private OFAction buildL3Modification(Instruction i) {
+        L3ModificationInstruction l3m = (L3ModificationInstruction) i;
+        ModIPInstruction ip;
+        OFOxm<?> oxm = null;
+        switch (l3m.subtype()) {
+        case IP_DST:
+            ip = (ModIPInstruction) i;
+            oxm = factory().oxms().ipv4Dst(IPv4Address.of(ip.ip().toInt()));
+        case IP_SRC:
+            ip = (ModIPInstruction) i;
+            oxm = factory().oxms().ipv4Src(IPv4Address.of(ip.ip().toInt()));
+        default:
+            log.warn("Unimplemented action type {}.", l3m.subtype());
+            break;
+        }
+
+        if (oxm != null) {
+            return factory().actions().buildSetField().setField(oxm).build();
+        }
+        return null;
+    }
+
+}
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index 8d3c018..7fbe09a 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -22,6 +22,7 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.flow.BatchOperation;
 import org.onlab.onos.net.flow.CompletedBatchOperation;
 import org.onlab.onos.net.flow.DefaultFlowEntry;
 import org.onlab.onos.net.flow.FlowEntry;
@@ -31,7 +32,6 @@
 import org.onlab.onos.net.flow.FlowRuleProvider;
 import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
 import org.onlab.onos.net.flow.FlowRuleProviderService;
-import org.onlab.onos.net.flow.BatchOperation;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.net.topology.TopologyService;
@@ -148,7 +148,7 @@
 
     private void applyRule(FlowRule flowRule) {
         OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
-        sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd());
+        sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory()).buildFlowAdd());
     }
 
 
@@ -163,7 +163,7 @@
 
     private void removeRule(FlowRule flowRule) {
         OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
-        sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
+        sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory()).buildFlowDel());
     }
 
     @Override
@@ -192,7 +192,7 @@
                 return failed;
             }
             sws.add(new Dpid(sw.getId()));
-            FlowModBuilder builder = new FlowModBuilder(flowRule, sw.factory());
+            FlowModBuilder builder = FlowModBuilder.builder(flowRule, sw.factory());
             switch (fbe.getOperator()) {
                 case ADD:
                     mod = builder.buildFlowAdd();