Fixes LinkCollection compiler
Changes:
- adds the ability to handle co-located ingress/egress points;
- adds new unit tests to test the proper handling;
Change-Id: I63da5057e716cc94fcca8f13debafc44633b6820
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java
index 2176a20..df87844 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java
@@ -260,6 +260,103 @@
}
/**
+ * Helper method which handles the proper generation of the ouput actions.
+ *
+ * @param outPorts the output ports
+ * @param deviceId the current device
+ * @param intent the intent to compile
+ * @param outLabels the output labels
+ * @param type the encapsulation type
+ * @param preCondition the previous state
+ * @param treatmentBuilder the builder to update with the ouput actions
+ */
+ private void manageOutputPorts(Set<PortNumber> outPorts,
+ DeviceId deviceId,
+ LinkCollectionIntent intent,
+ Map<ConnectPoint, Identifier<?>> outLabels,
+ EncapsulationType type,
+ TrafficSelector.Builder preCondition,
+ TrafficTreatment.Builder treatmentBuilder) {
+ /*
+ * We need to order the actions. First the actions
+ * related to the not-egress points. At the same time we collect
+ * also the egress points.
+ */
+ List<FilteredConnectPoint> egressPoints = Lists.newArrayList();
+ for (PortNumber outPort : outPorts) {
+ Optional<FilteredConnectPoint> filteredEgressPoint =
+ getFilteredConnectPointFromIntent(deviceId, outPort, intent);
+ if (!filteredEgressPoint.isPresent()) {
+ /*
+ * We build a temporary selector for the encapsulation.
+ */
+ TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
+ /*
+ * We retrieve the associated label to the output port.
+ */
+ ConnectPoint cp = new ConnectPoint(deviceId, outPort);
+ Identifier<?> outLabel = outLabels.get(cp);
+ /*
+ * If there are not labels, we cannot handle.
+ */
+ if (outLabel == null) {
+ throw new IntentCompilationException(String.format(NO_LABELS, cp));
+ }
+ /*
+ * In the core we match using encapsulation.
+ */
+ updateSelectorFromEncapsulation(
+ encapBuilder,
+ type,
+ outLabel
+ );
+ /*
+ * We generate the transition.
+ */
+ TrafficTreatment forwardingTreatment =
+ forwardingTreatment(preCondition.build(),
+ encapBuilder.build(),
+ getEthType(intent.selector()));
+ /*
+ * We add the instruction necessary to the transition.
+ */
+ forwardingTreatment.allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ /*
+ * Finally we set the output action.
+ */
+ treatmentBuilder.setOutput(outPort);
+ /*
+ * The encapsulation modifies the packet. If we are optimizing
+ * we have to update the state.
+ */
+ if (optimize) {
+ preCondition = encapBuilder;
+ }
+ } else {
+ egressPoints.add(filteredEgressPoint.get());
+ }
+ }
+ /*
+ * The idea is to order the egress points. Before we deal
+ * with the egress points which looks like similar to the
+ * selector derived from the previous state then the
+ * the others.
+ */
+ TrafficSelector prevState = preCondition.build();
+ if (optimize) {
+ egressPoints = orderedEgressPoints(prevState, egressPoints);
+ }
+ /*
+ * In this case, we have to transit to the final
+ * state.
+ */
+ generateEgressActions(treatmentBuilder, egressPoints, prevState, intent);
+
+ }
+
+ /**
* Helper method to generate the egress actions.
*
* @param treatmentBuilder the treatment builder to update
@@ -654,60 +751,23 @@
.criteria()
.forEach(selectorBuilder::add);
/*
- * In this scenario, we can have several output ports.
+ * In this case the precondition is the selector of the filtered
+ * ingress point.
*/
- outPorts.forEach(outPort -> {
- Optional<FilteredConnectPoint> filteredEgressPoint =
- getFilteredConnectPointFromIntent(deviceId, outPort, intent);
- /*
- * If we are at the egress, we don't handle
- * with encapsulation. Error scenario
- */
- if (filteredEgressPoint.isPresent()) {
- throw new IntentCompilationException(WRONG_ENCAPSULATION);
- }
- /*
- * Transit/core, we have to transit to the intermediate
- * state. We build a temporary selector for the encapsulation.
- */
- TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
- /*
- * We retrieve the associated label to the output port.
- */
- ConnectPoint cp = new ConnectPoint(deviceId, outPort);
- Identifier<?> outLabel = outLabels.get(cp);
- /*
- * If there aren't labels, we cannot handle.
- */
- if (outLabel == null) {
- throw new IntentCompilationException(String.format(NO_LABELS, cp));
- }
- /*
- * In the core we match using encapsulation.
- */
- updateSelectorFromEncapsulation(
- encapBuilder,
- type,
- outLabel
- );
- /*
- * We generate the transition.
- */
- TrafficTreatment forwardingTreatment =
- forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
- encapBuilder.build(),
- getEthType(intent.selector()));
- /*
- * We add the instruction necessary to the transition.
- */
- forwardingTreatment.allInstructions().stream()
- .filter(inst -> inst.type() != Instruction.Type.NOACTION)
- .forEach(treatmentBuilder::add);
- /*
- * Finally we set the output action.
- */
- treatmentBuilder.setOutput(outPort);
- });
+ TrafficSelector.Builder preCondition = DefaultTrafficSelector
+ .builder(filteredIngressPoint.get().trafficSelector());
+ /*
+ * Generate the output actions.
+ */
+ manageOutputPorts(
+ outPorts,
+ deviceId,
+ intent,
+ outLabels,
+ type,
+ preCondition,
+ treatmentBuilder
+ );
}
@@ -751,74 +811,18 @@
inLabel
);
/*
- * We need to order the actions. First the actions
- * related to the not-egress points. At the same time we collect
- * also the egress points.
+ * Generate the output actions.
*/
- List<FilteredConnectPoint> egressPoints = Lists.newArrayList();
- for (PortNumber outPort : outPorts) {
- Optional<FilteredConnectPoint> filteredEgressPoint =
- getFilteredConnectPointFromIntent(deviceId, outPort, intent);
- if (!filteredEgressPoint.isPresent()) {
- /*
- * We build a temporary selector for the encapsulation.
- */
- TrafficSelector.Builder encapBuilder = DefaultTrafficSelector.builder();
- /*
- * We retrieve the associated label to the output port.
- */
- ConnectPoint cp = new ConnectPoint(deviceId, outPort);
- Identifier<?> outLabel = outLabels.get(cp);
- /*
- * If there are not labels, we cannot handle.
- */
- if (outLabel == null) {
- throw new IntentCompilationException(String.format(NO_LABELS, cp));
- }
- /*
- * In the core we match using encapsulation.
- */
- updateSelectorFromEncapsulation(
- encapBuilder,
- type,
- outLabel
- );
- /*
- * We generate the transition.
- */
- TrafficTreatment forwardingTreatment =
- forwardingTreatment(selectorBuilder.build(),
- encapBuilder.build(),
- getEthType(intent.selector()));
- /*
- * We add the instruction necessary to the transition.
- */
- forwardingTreatment.allInstructions().stream()
- .filter(inst -> inst.type() != Instruction.Type.NOACTION)
- .forEach(treatmentBuilder::add);
- /*
- * Finally we set the output action.
- */
- treatmentBuilder.setOutput(outPort);
- } else {
- egressPoints.add(filteredEgressPoint.get());
- }
- }
- /*
- * The idea is to order the egress points. Before we deal
- * with the egress points which looks like similar to the
- * selector derived from the encpsulation constraint then
- * the others.
- */
- TrafficSelector prevState = selectorBuilder.build();
- if (optimize) {
- egressPoints = orderedEgressPoints(prevState, egressPoints);
- }
- /*
- * In this case, we have to transit to the final
- * state.
- */
- generateEgressActions(treatmentBuilder, egressPoints, prevState, intent);
+ manageOutputPorts(
+ outPorts,
+ deviceId,
+ intent,
+ outLabels,
+ type,
+ selectorBuilder,
+ treatmentBuilder
+ );
+
}
/**