[ONOS-7131] Add Interpreter for fabric.p4
Change-Id: I21e36f968555b3c375e6009072764442e2a10270
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
new file mode 100644
index 0000000..a2e4974
--- /dev/null
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.pipelines.fabric;
+
+import com.google.common.collect.ImmutableList;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onlab.util.ImmutableByteSequence;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.pi.model.PiActionId;
+import org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
+import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionParam;
+
+import java.util.List;
+
+import static java.lang.String.format;
+import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
+import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
+
+
+final class FabricTreatmentInterpreter {
+ private static final String INVALID_TREATMENT = "Invalid treatment for %s block: %s";
+
+ // Hide default constructor
+ protected FabricTreatmentInterpreter() {
+ }
+
+ /*
+ * In Filtering block, we need to implement these actions:
+ *
+ * push_internal_vlan
+ * set_vlan
+ * nop
+ *
+ * Unsupported, using PiAction directly:
+ * set_forwarding_type
+ */
+
+ static PiAction mapFilteringTreatment(TrafficTreatment treatment)
+ throws PiInterpreterException {
+ List<Instruction> instructions = treatment.allInstructions();
+ Instruction noActInst = Instructions.createNoAction();
+ if (instructions.isEmpty() || instructions.contains(noActInst)) {
+ // nop
+ return PiAction.builder()
+ .withId(FabricConstants.ACT_NOP_ID)
+ .build();
+ }
+
+ L2ModificationInstruction.ModVlanHeaderInstruction pushVlanInst = null;
+ ModVlanIdInstruction setVlanInst = null;
+
+ for (Instruction inst : instructions) {
+ if (inst.type() == L2MODIFICATION) {
+ L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
+
+ if (l2Inst.subtype() == VLAN_PUSH) {
+ pushVlanInst = (L2ModificationInstruction.ModVlanHeaderInstruction) l2Inst;
+
+ } else if (l2Inst.subtype() == VLAN_ID) {
+ setVlanInst = (ModVlanIdInstruction) l2Inst;
+ }
+ }
+ }
+
+ if (setVlanInst == null) {
+ throw new PiInterpreterException(format(INVALID_TREATMENT, "filtering", treatment));
+ }
+
+ VlanId vlanId = setVlanInst.vlanId();
+ PiActionParam param = new PiActionParam(FabricConstants.ACT_PRM_NEW_VLAN_ID_ID,
+ ImmutableByteSequence.copyFrom(vlanId.toShort()));
+ PiActionId actionId;
+ if (pushVlanInst != null) {
+ // push_internal_vlan
+ actionId = FabricConstants.ACT_PUSH_INTERNAL_VLAN_ID;
+ } else {
+ actionId = FabricConstants.ACT_SET_VLAN_ID;
+ }
+
+ // set_vlan
+ return PiAction.builder()
+ .withId(actionId)
+ .withParameter(param)
+ .build();
+ }
+
+ /*
+ * In forwarding block, we need to implement these actions:
+ * duplicate_to_controller
+ *
+ * Unsupported, using PiAction directly:
+ * set_next_id
+ * push_mpls_and_next_v4
+ * push_mpls_and_next_v6
+ */
+
+ public static PiAction mapForwardingTreatment(TrafficTreatment treatment)
+ throws PiInterpreterException {
+ List<Instruction> insts = treatment.allInstructions();
+ OutputInstruction outInst = insts.stream()
+ .filter(inst -> inst.type() == OUTPUT)
+ .map(inst -> (OutputInstruction) inst)
+ .findFirst()
+ .orElse(null);
+
+ if (outInst == null) {
+ throw new PiInterpreterException(format(INVALID_TREATMENT, "forwarding", treatment));
+ }
+
+ PortNumber portNumber = outInst.port();
+ if (!portNumber.equals(PortNumber.CONTROLLER)) {
+ throw new PiInterpreterException(format("Unsupported port number %s," +
+ "supports punt action only",
+ portNumber));
+ }
+
+ return PiAction.builder()
+ .withId(FabricConstants.ACT_DUPLICATE_TO_CONTROLLER_ID)
+ .build();
+ }
+
+ /*
+ * In Next block, we need to implement these actions:
+ * output
+ * output_ecmp
+ * set_vlan_output
+ *
+ * Unsupported, using PiAction directly:
+ * set_mcast_group
+ */
+
+ public static PiAction mapNextTreatment(TrafficTreatment treatment)
+ throws PiInterpreterException {
+ List<Instruction> insts = treatment.allInstructions();
+ OutputInstruction outInst = null;
+ ModEtherInstruction modEthDstInst = null;
+ ModEtherInstruction modEthSrcInst = null;
+ ModVlanIdInstruction modVlanIdInst = null;
+
+ // TODO: use matrix to store the combination of instruction
+ for (Instruction inst : insts) {
+ switch (inst.type()) {
+ case L2MODIFICATION:
+ L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
+
+ if (l2Inst.subtype() == ETH_SRC) {
+ modEthSrcInst = (ModEtherInstruction) l2Inst;
+ }
+
+ if (l2Inst.subtype() == ETH_DST) {
+ modEthDstInst = (ModEtherInstruction) l2Inst;
+ }
+
+ if (l2Inst.subtype() == VLAN_ID) {
+ modVlanIdInst = (ModVlanIdInstruction) l2Inst;
+ }
+ break;
+ case OUTPUT:
+ outInst = (OutputInstruction) inst;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (outInst == null) {
+ throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
+ }
+ short portNum = (short) outInst.port().toLong();
+ PiActionParam portNumParam = new PiActionParam(FabricConstants.ACT_PRM_PORT_NUM_ID,
+ ImmutableByteSequence.copyFrom(portNum));
+ if (modEthDstInst == null && modEthSrcInst == null) {
+ if (modVlanIdInst != null) {
+ VlanId vlanId = modVlanIdInst.vlanId();
+ PiActionParam vlanParam =
+ new PiActionParam(FabricConstants.ACT_PRM_NEW_VLAN_ID_ID,
+ ImmutableByteSequence.copyFrom(vlanId.toShort()));
+ // set_vlan_output
+ return PiAction.builder()
+ .withId(FabricConstants.ACT_SET_VLAN_OUTPUT_ID)
+ .withParameters(ImmutableList.of(portNumParam, vlanParam))
+ .build();
+ } else {
+ // output
+ return PiAction.builder()
+ .withId(FabricConstants.ACT_OUTPUT_ID)
+ .withParameter(portNumParam)
+ .build();
+ }
+ }
+
+ if (modEthDstInst != null && modEthSrcInst != null) {
+ // output and rewrite src/dst mac
+ MacAddress srcMac = modEthSrcInst.mac();
+ MacAddress dstMac = modEthDstInst.mac();
+ PiActionParam srcMacParam = new PiActionParam(FabricConstants.ACT_PRM_SMAC_ID,
+ ImmutableByteSequence.copyFrom(srcMac.toBytes()));
+ PiActionParam dstMacParam = new PiActionParam(FabricConstants.ACT_PRM_DMAC_ID,
+ ImmutableByteSequence.copyFrom(dstMac.toBytes()));
+ return PiAction.builder()
+ .withId(FabricConstants.ACT_L3_ROUTING_ID)
+ .withParameters(ImmutableList.of(portNumParam,
+ srcMacParam,
+ dstMacParam))
+ .build();
+ }
+
+ throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
+ }
+}