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/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;
+ }
+
+}