[SDFAB-102] Backport changes required for policies to fabric.p4 (Redirect)
Change-Id: I357c908d31abad9c3f8d74723d937ea948e54808
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/Constants.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/Constants.java
new file mode 100644
index 0000000..f55a825
--- /dev/null
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/Constants.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2021-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.impl.behaviour;
+
+/**
+ * Constant values.
+ */
+public final class Constants {
+
+ // Used with is_infra_port metadata
+ public static final byte[] ONE = new byte[]{1};
+ public static final byte[] ZERO = new byte[]{0};
+
+ public static final long PORT_TYPE_MASK = 0x3;
+ public static final byte PORT_TYPE_EDGE = 0x1;
+ public static final byte PORT_TYPE_INFRA = 0x2;
+ public static final byte PORT_TYPE_INTERNAL = 0x3;
+
+ // Forwarding types from P4 program (not exposed in P4Info).
+ public static final byte FWD_MPLS = 1;
+ public static final byte FWD_IPV4_ROUTING = 2;
+ public static final byte FWD_IPV6_ROUTING = 4;
+
+ public static final short ETH_TYPE_EXACT_MASK = (short) 0xFFFF;
+
+ public static final int DEFAULT_VLAN = 4094;
+ public static final int DEFAULT_PW_TRANSPORT_VLAN = 4090;
+
+ // hide default constructor
+ private Constants() {
+ }
+}
\ No newline at end of file
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricCapabilities.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricCapabilities.java
index fbb709a..93605e2 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricCapabilities.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricCapabilities.java
@@ -81,9 +81,9 @@
public boolean supportDoubleVlanTerm() {
if (pipeconf.pipelineModel()
- .table(FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN).isPresent()) {
- return pipeconf.pipelineModel().table(FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN)
- .get().action(FabricConstants.FABRIC_INGRESS_NEXT_SET_DOUBLE_VLAN)
+ .table(FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_VLAN).isPresent()) {
+ return pipeconf.pipelineModel().table(FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_VLAN)
+ .get().action(FabricConstants.FABRIC_INGRESS_PRE_NEXT_SET_DOUBLE_VLAN)
.isPresent();
}
return false;
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricInterpreter.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricInterpreter.java
index 4ed412d..1a7b2ba 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricInterpreter.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricInterpreter.java
@@ -68,18 +68,17 @@
public static final byte[] ZERO = new byte[]{0};
// Group tables by control block.
- private static final Set<PiTableId> FILTERING_CTRL_TBLS = ImmutableSet.of(
- FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
- FabricConstants.FABRIC_INGRESS_FILTERING_FWD_CLASSIFIER);
private static final Set<PiTableId> FORWARDING_CTRL_TBLS = ImmutableSet.of(
FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS,
FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V6,
FabricConstants.FABRIC_INGRESS_FORWARDING_BRIDGING);
+ private static final Set<PiTableId> PRE_NEXT_CTRL_TBLS = ImmutableSet.of(
+ FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_MPLS,
+ FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_VLAN);
private static final Set<PiTableId> ACL_CTRL_TBLS = ImmutableSet.of(
FabricConstants.FABRIC_INGRESS_ACL_ACL);
private static final Set<PiTableId> NEXT_CTRL_TBLS = ImmutableSet.of(
- FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN,
FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE,
FabricConstants.FABRIC_INGRESS_NEXT_HASHED,
FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT);
@@ -166,10 +165,10 @@
@Override
public PiAction mapTreatment(TrafficTreatment treatment, PiTableId piTableId)
throws PiInterpreterException {
- if (FILTERING_CTRL_TBLS.contains(piTableId)) {
- return treatmentInterpreter.mapFilteringTreatment(treatment, piTableId);
- } else if (FORWARDING_CTRL_TBLS.contains(piTableId)) {
+ if (FORWARDING_CTRL_TBLS.contains(piTableId)) {
return treatmentInterpreter.mapForwardingTreatment(treatment, piTableId);
+ } else if (PRE_NEXT_CTRL_TBLS.contains(piTableId)) {
+ return treatmentInterpreter.mapPreNextTreatment(treatment, piTableId);
} else if (ACL_CTRL_TBLS.contains(piTableId)) {
return treatmentInterpreter.mapAclTreatment(treatment, piTableId);
} else if (NEXT_CTRL_TBLS.contains(piTableId)) {
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java
index fe2d490..bdf3eaf 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricTreatmentInterpreter.java
@@ -41,13 +41,14 @@
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.MPLS_LABEL;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_PUSH;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.instruction;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instruction;
+import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2InstructionOrFail;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instructions;
+import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.treatmentException;
/**
* Treatment translation logic.
@@ -57,8 +58,6 @@
private final FabricCapabilities capabilities;
private static final ImmutableMap<PiTableId, PiActionId> NOP_ACTIONS =
ImmutableMap.<PiTableId, PiActionId>builder()
- .put(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
- FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
.put(FabricConstants.FABRIC_INGRESS_FORWARDING_ROUTING_V4,
FabricConstants.FABRIC_INGRESS_FORWARDING_NOP_ROUTING_V4)
.put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
@@ -72,34 +71,10 @@
this.capabilities = capabilities;
}
- static PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId)
- throws PiInterpreterException {
-
- if (!tableId.equals(FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN)) {
- // Mapping for other tables of the filtering block must be handled
- // in the pipeliner.
- tableException(tableId);
- }
-
- // VLAN_POP action is equivalent to the permit action (VLANs pop is done anyway)
- if (isFilteringNoAction(treatment) || isFilteringPopAction(treatment)) {
- // Permit action if table is ingress_port_vlan;
- return nop(tableId);
- }
-
- final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
- treatment, VLAN_ID, tableId);
- return PiAction.builder()
- .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
- .withParameter(new PiActionParam(
- FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
- .build();
- }
-
static PiAction mapForwardingTreatment(TrafficTreatment treatment, PiTableId tableId)
throws PiInterpreterException {
- if (isForwardingNoAction(treatment)) {
+ if (isNoAction(treatment)) {
return nop(tableId);
}
treatmentException(
@@ -108,35 +83,58 @@
return null;
}
- PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
+ PiAction mapPreNextTreatment(TrafficTreatment treatment, PiTableId tableId)
throws PiInterpreterException {
- if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN) {
+ if (tableId == FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_MPLS) {
+ return mapNextMplsTreatment(treatment, tableId);
+ } else if (tableId == FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_VLAN) {
return mapNextVlanTreatment(treatment, tableId);
- } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_HASHED) {
- return mapNextHashedOrSimpleTreatment(treatment, tableId, false);
- } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE) {
- return mapNextHashedOrSimpleTreatment(treatment, tableId, true);
- } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT) {
- return mapNextXconnect(treatment, tableId);
}
throw new PiInterpreterException(format(
"Treatment mapping not supported for table '%s'", tableId));
}
+ PiAction mapNextTreatment(TrafficTreatment treatment, PiTableId tableId)
+ throws PiInterpreterException {
+ if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_HASHED) {
+ return mapNextHashedOrSimpleTreatment(treatment, tableId, false);
+ } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_SIMPLE) {
+ return mapNextHashedOrSimpleTreatment(treatment, tableId, true);
+ } else if (tableId == FabricConstants.FABRIC_INGRESS_NEXT_XCONNECT) {
+ return mapNextXconnect(treatment, tableId);
+ }
+ throw new PiInterpreterException(format(
+ "Treatment mapping not supported for table '%s'", tableId));
+ }
+
+ private static PiAction mapNextMplsTreatment(TrafficTreatment treatment, PiTableId tableId)
+ throws PiInterpreterException {
+ final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
+ treatment, MPLS_LABEL);
+ if (mplsLabel != null) {
+ return PiAction.builder()
+ .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
+ .withId(FabricConstants.FABRIC_INGRESS_PRE_NEXT_SET_MPLS_LABEL)
+ .build();
+ }
+ throw new PiInterpreterException("There is no MPLS instruction");
+ }
+
private PiAction mapNextVlanTreatment(TrafficTreatment treatment, PiTableId tableId)
throws PiInterpreterException {
final List<ModVlanIdInstruction> modVlanIdInst = l2InstructionsOrFail(treatment, VLAN_ID, tableId)
.stream().map(i -> (ModVlanIdInstruction) i).collect(Collectors.toList());
if (modVlanIdInst.size() == 1) {
- return PiAction.builder().withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_VLAN)
+ return PiAction.builder().withId(FabricConstants.FABRIC_INGRESS_PRE_NEXT_SET_VLAN)
.withParameter(new PiActionParam(
FabricConstants.VLAN_ID,
modVlanIdInst.get(0).vlanId().toShort()))
.build();
}
+ // next_vlan has been moved to pre_next
if (modVlanIdInst.size() == 2 && capabilities.supportDoubleVlanTerm()) {
return PiAction.builder()
- .withId(FabricConstants.FABRIC_INGRESS_NEXT_SET_DOUBLE_VLAN)
+ .withId(FabricConstants.FABRIC_INGRESS_PRE_NEXT_SET_DOUBLE_VLAN)
.withParameter(new PiActionParam(
FabricConstants.INNER_VLAN_ID,
modVlanIdInst.get(0).vlanId().toShort()))
@@ -151,20 +149,15 @@
private static PiAction mapNextHashedOrSimpleTreatment(
TrafficTreatment treatment, PiTableId tableId, boolean simple)
throws PiInterpreterException {
- // Provide mapping for output_hashed, routing_hashed, and
- // mpls_routing_hashed. multicast_hashed can only be invoked with
- // PiAction, hence no mapping. outPort required for all actions. Presence
- // of other instructions will determine which action to map to.
+ // Provide mapping for output_hashed and routing_hashed; multicast_hashed
+ // can only be invoked with PiAction, hence no mapping. outPort required for
+ // all actions. Presence of other instructions will determine which action to map to.
final PortNumber outPort = ((OutputInstruction) instructionOrFail(
treatment, OUTPUT, tableId)).port();
final ModEtherInstruction ethDst = (ModEtherInstruction) l2Instruction(
treatment, ETH_DST);
final ModEtherInstruction ethSrc = (ModEtherInstruction) l2Instruction(
treatment, ETH_SRC);
- final Instruction mplsPush = l2Instruction(
- treatment, MPLS_PUSH);
- final ModMplsLabelInstruction mplsLabel = (ModMplsLabelInstruction) l2Instruction(
- treatment, MPLS_LABEL);
final PiAction.Builder actionBuilder = PiAction.builder()
.withParameter(new PiActionParam(FabricConstants.PORT_NUM, outPort.toLong()));
@@ -174,20 +167,11 @@
FabricConstants.SMAC, ethSrc.mac().toBytes()));
actionBuilder.withParameter(new PiActionParam(
FabricConstants.DMAC, ethDst.mac().toBytes()));
- if (mplsLabel != null) {
- // mpls_routing_hashed
- return actionBuilder
- .withParameter(new PiActionParam(FabricConstants.LABEL, mplsLabel.label().toInt()))
- .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_SIMPLE
- : FabricConstants.FABRIC_INGRESS_NEXT_MPLS_ROUTING_HASHED)
- .build();
- } else {
- // routing_hashed
- return actionBuilder
- .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
- : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
- .build();
- }
+ // routing_hashed
+ return actionBuilder
+ .withId(simple ? FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_SIMPLE
+ : FabricConstants.FABRIC_INGRESS_NEXT_ROUTING_HASHED)
+ .build();
} else {
// output_hashed
return actionBuilder
@@ -214,7 +198,7 @@
if (isDrop(treatment)) {
return drop(tableId);
}
- if (isForwardingNoAction(treatment)) {
+ if (isNoAction(treatment)) {
return nop(tableId);
}
treatmentException(
@@ -256,15 +240,8 @@
return PiAction.builder().withId(FabricConstants.FABRIC_INGRESS_ACL_DROP).build();
}
- // NOTE: we use clearDeferred to signal when there are no more ports associated to a given vlan
- private static boolean isFilteringNoAction(TrafficTreatment treatment) {
- return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
- (treatment.allInstructions().isEmpty()) ||
- (treatment.allInstructions().size() == 1 && treatment.writeMetadata() != null);
- }
-
// NOTE: clearDeferred is used by the routing application to implement ACL drop and route black-holing
- private static boolean isForwardingNoAction(TrafficTreatment treatment) {
+ private static boolean isNoAction(TrafficTreatment treatment) {
return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
(treatment.allInstructions().isEmpty() && !treatment.clearedDeferred()) ||
(treatment.allInstructions().size() == 1 && treatment.writeMetadata() != null);
@@ -274,21 +251,6 @@
return treatment.allInstructions().isEmpty() && treatment.clearedDeferred();
}
- private static boolean isFilteringPopAction(TrafficTreatment treatment) {
- return l2Instruction(treatment, VLAN_POP) != null;
- }
-
- private static Instruction l2InstructionOrFail(
- TrafficTreatment treatment,
- L2ModificationInstruction.L2SubType subType, PiTableId tableId)
- throws PiInterpreterException {
- final Instruction inst = l2Instruction(treatment, subType);
- if (inst == null) {
- treatmentException(tableId, treatment, format("missing %s instruction", subType));
- }
- return inst;
- }
-
private static List<L2ModificationInstruction> l2InstructionsOrFail(
TrafficTreatment treatment,
L2ModificationInstruction.L2SubType subType, PiTableId tableId)
@@ -309,16 +271,4 @@
}
return inst;
}
-
- private static void tableException(PiTableId tableId)
- throws PiInterpreterException {
- throw new PiInterpreterException(format("Table '%s' not supported", tableId));
- }
-
- private static void treatmentException(
- PiTableId tableId, TrafficTreatment treatment, String explanation)
- throws PiInterpreterException {
- throw new PiInterpreterException(format(
- "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
- }
}
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricUtils.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricUtils.java
index 655f88d..4496f19 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricUtils.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/FabricUtils.java
@@ -25,6 +25,8 @@
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flowobjective.DefaultNextTreatment;
import org.onosproject.net.flowobjective.NextTreatment;
+import org.onosproject.net.pi.model.PiPipelineInterpreter;
+import org.onosproject.net.pi.model.PiTableId;
import java.util.Collection;
import java.util.List;
@@ -62,11 +64,10 @@
format("%s criterion cannot be null", type));
}
- public static Instructions.OutputInstruction instruction(TrafficTreatment treatment, Instruction.Type type) {
+ public static Instruction instruction(TrafficTreatment treatment, Instruction.Type type) {
return treatment.allInstructions()
.stream()
.filter(inst -> inst.type() == type)
- .map(inst -> (Instructions.OutputInstruction) inst)
.findFirst().orElse(null);
}
@@ -79,6 +80,17 @@
.findFirst().orElse(null);
}
+ public static Instruction l2InstructionOrFail(
+ TrafficTreatment treatment,
+ L2ModificationInstruction.L2SubType subType, PiTableId tableId)
+ throws PiPipelineInterpreter.PiInterpreterException {
+ final Instruction inst = l2Instruction(treatment, subType);
+ if (inst == null) {
+ treatmentException(tableId, treatment, format("missing %s instruction", subType));
+ }
+ return inst;
+ }
+
public static List<L2ModificationInstruction> l2Instructions(
TrafficTreatment treatment, L2ModificationInstruction.L2SubType subType) {
return treatment.allInstructions().stream()
@@ -89,7 +101,7 @@
}
public static Instructions.OutputInstruction outputInstruction(TrafficTreatment treatment) {
- return instruction(treatment, Instruction.Type.OUTPUT);
+ return (Instructions.OutputInstruction) instruction(treatment, Instruction.Type.OUTPUT);
}
public static PortNumber outputPort(TrafficTreatment treatment) {
@@ -104,4 +116,11 @@
}
return null;
}
+
+ public static void treatmentException(
+ PiTableId tableId, TrafficTreatment treatment, String explanation)
+ throws PiPipelineInterpreter.PiInterpreterException {
+ throw new PiPipelineInterpreter.PiInterpreterException(format(
+ "Invalid treatment for table '%s', %s: %s", tableId, explanation, treatment));
+ }
}
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java
index 744cd9d..3105e66 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java
@@ -80,7 +80,8 @@
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricInterpreter.ONE;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricInterpreter.ZERO;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.outputPort;
-import static org.onosproject.pipelines.fabric.impl.behaviour.pipeliner.FilteringObjectiveTranslator.FWD_IPV4_ROUTING;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV4_ROUTING;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_INTERNAL;
import static org.slf4j.LoggerFactory.getLogger;
/**
@@ -368,6 +369,7 @@
.withId(vlanValid ? FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT
: FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
.withParameter(new PiActionParam(FabricConstants.VLAN_ID, vlanId))
+ .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, PORT_TYPE_INTERNAL))
.build())
.build();
return DefaultFlowRule.builder()
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java
index 39d100e..bfdcc2b 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FilteringObjectiveTranslator.java
@@ -33,10 +33,12 @@
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instructions;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.pi.model.PiTableId;
import org.onosproject.net.pi.runtime.PiAction;
import org.onosproject.net.pi.runtime.PiActionParam;
import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
@@ -49,7 +51,23 @@
import static java.lang.String.format;
import static org.onosproject.net.flow.criteria.Criterion.Type.INNER_VLAN_VID;
import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
+import static org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.DEFAULT_VLAN;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.DEFAULT_PW_TRANSPORT_VLAN;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ETH_TYPE_EXACT_MASK;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_MPLS;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV4_ROUTING;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.FWD_IPV6_ROUTING;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ONE;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_EDGE;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_INFRA;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.ZERO;
+import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2InstructionOrFail;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;
+import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.l2Instruction;
+
/**
* ObjectiveTranslator implementation for FilteringObjective.
@@ -57,16 +75,6 @@
class FilteringObjectiveTranslator
extends AbstractObjectiveTranslator<FilteringObjective> {
- // Forwarding types from fabric.p4.
- static final byte FWD_MPLS = 1;
- static final byte FWD_IPV4_ROUTING = 2;
- static final byte FWD_IPV6_ROUTING = 3;
-
- private static final byte[] ONE = new byte[]{1};
- private static final byte[] ZERO = new byte[]{0};
-
- private static final short ETH_TYPE_EXACT_MASK = (short) 0xFFFF;
-
private static final PiAction DENY = PiAction.builder()
.withId(FabricConstants.FABRIC_INGRESS_FILTERING_DENY)
.build();
@@ -168,7 +176,7 @@
private boolean isDoubleTagged(FilteringObjective obj) {
return obj.meta() != null &&
- FabricUtils.l2Instruction(obj.meta(), L2ModificationInstruction.L2SubType.VLAN_POP) != null &&
+ FabricUtils.l2Instruction(obj.meta(), L2SubType.VLAN_POP) != null &&
FabricUtils.criterion(obj.conditions(), VLAN_VID) != null &&
FabricUtils.criterion(obj.conditions(), INNER_VLAN_VID) != null;
}
@@ -206,18 +214,66 @@
selector.add(innerVlanCriterion);
}
- final TrafficTreatment treatment;
+ final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
if (obj.type().equals(FilteringObjective.Type.DENY)) {
- treatment = DefaultTrafficTreatment.builder()
- .piTableAction(DENY)
- .build();
+ treatmentBuilder.piTableAction(DENY);
} else {
- treatment = obj.meta() == null
- ? DefaultTrafficTreatment.emptyTreatment() : obj.meta();
+ byte portType = PORT_TYPE_EDGE;
+ if (!innerVlanValid && outerVlanValid &&
+ outerVlanCriterion.vlanId().toShort() == DEFAULT_PW_TRANSPORT_VLAN) {
+ portType = PORT_TYPE_INFRA;
+ } else if (obj.meta() != null) {
+ ModVlanIdInstruction modVlanIdInstruction = (ModVlanIdInstruction) l2Instruction(obj.meta(), VLAN_ID);
+ if (modVlanIdInstruction != null && modVlanIdInstruction.vlanId().toShort() == DEFAULT_VLAN) {
+ portType = PORT_TYPE_INFRA;
+ }
+ }
+ try {
+ treatmentBuilder.piTableAction(mapFilteringTreatment(obj.meta(),
+ FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN, portType));
+ } catch (PiInterpreterException ex) {
+ throw new FabricPipelinerException(format("Unable to map treatment for table '%s': %s",
+ FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
+ ex.getMessage()), ObjectiveError.UNSUPPORTED);
+ }
}
resultBuilder.addFlowRule(flowRule(
obj, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN,
- selector.build(), treatment));
+ selector.build(), treatmentBuilder.build()));
+ }
+
+ private PiAction mapFilteringTreatment(TrafficTreatment treatment, PiTableId tableId, byte portType)
+ throws PiInterpreterException {
+ if (treatment == null) {
+ treatment = DefaultTrafficTreatment.emptyTreatment();
+ }
+ // VLAN_POP action is equivalent to the permit action (VLANs pop is done anyway)
+ if (isFilteringNoAction(treatment) || isFilteringPopAction(treatment)) {
+ // Permit action if table is ingress_port_vlan;
+ return PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT)
+ .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, portType))
+ .build();
+ }
+
+ final ModVlanIdInstruction setVlanInst = (ModVlanIdInstruction) l2InstructionOrFail(
+ treatment, VLAN_ID, tableId);
+ return PiAction.builder()
+ .withId(FabricConstants.FABRIC_INGRESS_FILTERING_PERMIT_WITH_INTERNAL_VLAN)
+ .withParameter(new PiActionParam(FabricConstants.VLAN_ID, setVlanInst.vlanId().toShort()))
+ .withParameter(new PiActionParam(FabricConstants.PORT_TYPE, portType))
+ .build();
+ }
+
+ // NOTE: we use clearDeferred to signal when there are no more ports associated to a given vlan
+ private static boolean isFilteringNoAction(TrafficTreatment treatment) {
+ return treatment.equals(DefaultTrafficTreatment.emptyTreatment()) ||
+ (treatment.allInstructions().isEmpty()) ||
+ (treatment.allInstructions().size() == 1 && treatment.writeMetadata() != null);
+ }
+
+ private boolean isFilteringPopAction(TrafficTreatment treatment) {
+ return l2Instruction(treatment, VLAN_POP) != null;
}
private void fwdClassifierRules(
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/ForwardingObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/ForwardingObjectiveTranslator.java
index 0ab5beb..d527228 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/ForwardingObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/ForwardingObjectiveTranslator.java
@@ -32,7 +32,9 @@
import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.MetadataCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
+import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.Objective;
@@ -59,6 +61,9 @@
import static org.onosproject.net.group.DefaultGroupBucket.createCloneGroupBucket;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterionNotNull;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.outputPort;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_MASK;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_EDGE;
+import static org.onosproject.pipelines.fabric.impl.behaviour.Constants.PORT_TYPE_INFRA;
/**
@@ -103,6 +108,8 @@
FabricConstants.FABRIC_INGRESS_FORWARDING_SET_NEXT_ID_ROUTING_V6)
.put(FabricConstants.FABRIC_INGRESS_FORWARDING_MPLS,
FabricConstants.FABRIC_INGRESS_FORWARDING_POP_MPLS_AND_NEXT)
+ .put(FabricConstants.FABRIC_INGRESS_ACL_ACL,
+ FabricConstants.FABRIC_INGRESS_ACL_SET_NEXT_ID_ACL)
.build();
ForwardingObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
@@ -290,8 +297,22 @@
return;
}
}
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(obj.selector());
+ // Meta are used to signal the port type which can be edge or infra
+ if (obj.meta() != null && obj.meta().getCriterion(Criterion.Type.METADATA) != null) {
+ long portType = ((MetadataCriterion) obj.meta().getCriterion(Criterion.Type.METADATA)).metadata();
+ if (portType == PORT_TYPE_EDGE || portType == PORT_TYPE_INFRA) {
+ selectorBuilder.matchPi(PiCriterion.builder()
+ .matchTernary(FabricConstants.HDR_PORT_TYPE, portType, PORT_TYPE_MASK)
+ .build());
+ } else {
+ throw new FabricPipelinerException(format("Port type '%s' is not allowed for table '%s'",
+ portType, FabricConstants.FABRIC_INGRESS_FILTERING_INGRESS_PORT_VLAN),
+ ObjectiveError.UNSUPPORTED);
+ }
+ }
resultBuilder.addFlowRule(flowRule(
- obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, obj.selector()));
+ obj, FabricConstants.FABRIC_INGRESS_ACL_ACL, selectorBuilder.build()));
}
private DefaultGroupDescription createCloneGroup(
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
index 8ecffb2..47b7ef6 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/NextObjectiveTranslator.java
@@ -17,6 +17,7 @@
package org.onosproject.pipelines.fabric.impl.behaviour.pipeliner;
import com.google.common.collect.Lists;
+import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
@@ -28,6 +29,7 @@
import org.onosproject.net.flow.criteria.PiCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
import org.onosproject.net.flowobjective.DefaultNextTreatment;
import org.onosproject.net.flowobjective.NextObjective;
@@ -57,6 +59,7 @@
import java.util.stream.Collectors;
import static java.lang.String.format;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.MPLS_LABEL;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
import static org.onosproject.pipelines.fabric.impl.behaviour.FabricUtils.criterion;
@@ -103,13 +106,55 @@
}
if (!isGroupModifyOp(obj)) {
- // Generate next VLAN rules.
+ // Generate next MPLS and VLAN rules.
+ nextMpls(obj, resultBuilder);
nextVlan(obj, resultBuilder);
}
return resultBuilder.build();
}
+ private void nextMpls(NextObjective obj,
+ ObjectiveTranslation.Builder resultBuilder)
+ throws FabricPipelinerException {
+ // Next objective can contain only one mpls push and one mpls label
+ // instruction. Pipeliner does not support other configurations.
+
+ final List<List<ModMplsLabelInstruction>> mplsInstructions = defaultNextTreatments(
+ obj.nextTreatments(), false).stream()
+ .map(defaultNextTreatment -> l2Instructions(defaultNextTreatment.treatment(), MPLS_LABEL)
+ .stream().map(v -> (ModMplsLabelInstruction) v)
+ .collect(Collectors.toList()))
+ .filter(l -> !l.isEmpty())
+ .collect(Collectors.toList());
+
+ if (mplsInstructions.isEmpty()) {
+ // No need to apply next mpls table
+ return;
+ }
+
+ // We expect one mpls label for each treatment and the label has to be the same
+ final Set<MplsLabel> mplsLabels = mplsInstructions.stream()
+ .flatMap(Collection::stream)
+ .map(ModMplsLabelInstruction::label)
+ .collect(Collectors.toSet());
+ if (obj.nextTreatments().size() != mplsInstructions.size() ||
+ mplsLabels.size() != 1) {
+ throw new FabricPipelinerException(
+ "Inconsistent MPLS_LABEL instructions, cannot process " +
+ "next_mpls rule. It is required that all " +
+ "treatments have the same MPLS_LABEL instructions.");
+ }
+ final TrafficSelector selector = nextIdSelector(obj.id());
+ final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+ .setMpls(mplsLabels.iterator().next())
+ .build();
+
+ resultBuilder.addFlowRule(flowRule(
+ obj, FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_MPLS,
+ selector, treatment));
+ }
+
private void nextVlan(NextObjective obj,
ObjectiveTranslation.Builder resultBuilder)
throws FabricPipelinerException {
@@ -169,7 +214,7 @@
final TrafficTreatment treatment = treatmentBuilder.build();
resultBuilder.addFlowRule(flowRule(
- obj, FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN,
+ obj, FabricConstants.FABRIC_INGRESS_PRE_NEXT_NEXT_VLAN,
selector, treatment));
}
@@ -258,7 +303,7 @@
if (obj.meta() != null && obj.meta().getCriterion(Criterion.Type.VLAN_VID) != null) {
egressVlan(outPort, obj, popVlanInst, resultBuilder);
} else {
- log.warn("NextObjective {} is trying to program {} without {} information",
+ log.debug("NextObjective {} is trying to program {} without {} information",
obj, FabricConstants.FABRIC_EGRESS_EGRESS_NEXT_EGRESS_VLAN,
obj.meta() == null ? "metadata" : "vlanId");
}