Support in fabric pipeliner for pushing double VLAN tag in Next obj
- Small modification to better support pop and route
- To support route and push we expect to receive a Next Objective with two VLAN_ID
- Added capability to check if the pipeline support double VLAN termination
Change-Id: I8bfbf61ccd838a069121e5ab4a804f695a446bac
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/AbstractObjectiveTranslator.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/AbstractObjectiveTranslator.java
index c1e2f4d..c2ca0ff 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/AbstractObjectiveTranslator.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/AbstractObjectiveTranslator.java
@@ -46,11 +46,12 @@
protected final FabricCapabilities capabilities;
protected final DeviceId deviceId;
- private final PiPipelineInterpreter interpreter = new FabricInterpreter();
+ private final PiPipelineInterpreter interpreter;
AbstractObjectiveTranslator(DeviceId deviceId, FabricCapabilities capabilities) {
this.deviceId = checkNotNull(deviceId);
this.capabilities = checkNotNull(capabilities);
+ this.interpreter = new FabricInterpreter(capabilities);
}
public ObjectiveTranslation translate(T obj) {
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
index 4bf1bb5..20cafde 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
@@ -38,6 +38,7 @@
import org.onosproject.net.group.GroupDescription;
import org.onosproject.net.group.GroupService;
import org.onosproject.pipelines.fabric.AbstractFabricHandlerBehavior;
+import org.onosproject.pipelines.fabric.FabricCapabilities;
import org.onosproject.store.serializers.KryoNamespaces;
import org.slf4j.Logger;
@@ -78,6 +79,23 @@
private final ExecutorService callbackExecutor = SharedExecutors.getPoolThreadExecutor();
+ /**
+ * Creates a new instance of this behavior with the given capabilities.
+ *
+ * @param capabilities capabilities
+ */
+ public FabricPipeliner(FabricCapabilities capabilities) {
+ super(capabilities);
+ }
+
+ /**
+ * Create a new instance of this behaviour. Used by the abstract projectable
+ * model (i.e., {@link org.onosproject.net.Device#as(Class)}.
+ */
+ public FabricPipeliner() {
+ super();
+ }
+
@Override
public void init(DeviceId deviceId, PipelinerContext context) {
this.deviceId = deviceId;
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/NextObjectiveTranslator.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/NextObjectiveTranslator.java
index ec1c64b..d06d383 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/NextObjectiveTranslator.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/NextObjectiveTranslator.java
@@ -61,6 +61,7 @@
import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_POP;
import static org.onosproject.pipelines.fabric.FabricUtils.criterion;
import static org.onosproject.pipelines.fabric.FabricUtils.l2Instruction;
+import static org.onosproject.pipelines.fabric.FabricUtils.l2Instructions;
import static org.onosproject.pipelines.fabric.FabricUtils.outputPort;
/**
@@ -112,35 +113,45 @@
private void nextVlan(NextObjective obj,
ObjectiveTranslation.Builder resultBuilder)
throws FabricPipelinerException {
+ // We expect NextObjective treatments to contain one or two VLAN instructions.
+ // If two, this treatment should be mapped to an action for double-vlan push.
+ // In fabric.p4, mapping next IDs to VLAN IDs is done by a direct table (next_vlan),
+ // for this reason, we also make sure that all treatments in the NextObjective
+ // have exactly the same VLAN instructions, as they will be mapped to a single action
- // Set the egress VLAN for this next ID. Expect a VLAN_ID instruction
- // in the treatment, or use what's in meta.
- final List<ModVlanIdInstruction> vlanInstructions = defaultNextTreatments(
+ // Try to extract VLAN instructions in the treatment,
+ // later we check if we support multiple VLAN termination.
+ final List<List<ModVlanIdInstruction>> vlanInstructions = defaultNextTreatments(
obj.nextTreatments(), false).stream()
- .map(t -> (ModVlanIdInstruction) l2Instruction(t.treatment(), VLAN_ID))
- .filter(Objects::nonNull)
+ .map(defaultNextTreatment ->
+ l2Instructions(defaultNextTreatment.treatment(), VLAN_ID)
+ .stream().map(v -> (ModVlanIdInstruction) v)
+ .collect(Collectors.toList()))
+ .filter(l -> !l.isEmpty())
.collect(Collectors.toList());
+
final VlanIdCriterion vlanIdCriterion = obj.meta() == null ? null
: (VlanIdCriterion) criterion(obj.meta().criteria(), Criterion.Type.VLAN_VID);
- VlanId vlanId;
+ final List<VlanId> vlanIdList;
if (vlanInstructions.isEmpty() && vlanIdCriterion == null) {
// No VLAN_ID to apply.
return;
- } else if (!vlanInstructions.isEmpty()) {
+ }
+ if (!vlanInstructions.isEmpty()) {
// Give priority to what found in the instructions.
- // Expect the same VLAN ID for all instructions.
- final Set<VlanId> vlanIds = vlanInstructions.stream()
- .map(ModVlanIdInstruction::vlanId)
+ // Expect the same VLAN ID (or two VLAN IDs in the same order) for all instructions.
+ final Set<List<VlanId>> vlanIds = vlanInstructions.stream()
+ .map(l -> l.stream().map(ModVlanIdInstruction::vlanId).collect(Collectors.toList()))
.collect(Collectors.toSet());
if (obj.nextTreatments().size() != vlanInstructions.size() ||
vlanIds.size() != 1) {
throw new FabricPipelinerException(
"Inconsistent VLAN_ID instructions, cannot process " +
"next_vlan rule. It is required that all " +
- "treatments have the same VLAN_ID instruction.");
+ "treatments have the same VLAN_ID instructions.");
}
- vlanId = vlanIds.iterator().next();
+ vlanIdList = vlanIds.iterator().next();
} else {
// Use the value in meta.
// FIXME: there should be no need to generate a next_vlan rule for
@@ -149,13 +160,13 @@
// existing packet fields. But, for some reason, if we remove this
// rule, traffic is not forwarded at spines. We might need to look
// at the way default VLANs are handled in fabric.p4.
- vlanId = vlanIdCriterion.vlanId();
+ vlanIdList = List.of(vlanIdCriterion.vlanId());
}
final TrafficSelector selector = nextIdSelector(obj.id());
- final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
- .setVlanId(vlanId)
- .build();
+ final TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+ vlanIdList.stream().forEach(vlanId -> treatmentBuilder.setVlanId(vlanId));
+ final TrafficTreatment treatment = treatmentBuilder.build();
resultBuilder.addFlowRule(flowRule(
obj, FabricConstants.FABRIC_INGRESS_NEXT_NEXT_VLAN,