Change the way 1.3 flow mods are built to support rewrite actions.

Change-Id: I9c1c3059822b19d0665702162dee9904f95127d8
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;
+    }
 
 }