[ONOS-5239] Adds encapsulation to LinkCollectionIntent
Changes:
- Adds encapsulation to LinkCollectionIntent;
- Cleans the code and adds comments;
- fixes ethertype issue for mplsPop
- Adds unit tests;
Change-Id: I4398426e73c5a9dd085689cb56162bd2c3b8f5af
diff --git a/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
index 8898008..842c86d 100644
--- a/core/api/src/test/java/org/onosproject/net/NetTestTools.java
+++ b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
@@ -15,12 +15,23 @@
*/
package org.onosproject.net;
+import com.google.common.collect.ImmutableList;
import org.onlab.junit.TestUtils;
import org.onlab.packet.ChassisId;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
import org.onosproject.TestApplicationId;
import org.onosproject.cluster.NodeId;
import org.onosproject.core.ApplicationId;
import org.onosproject.event.EventDeliveryService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
import org.onosproject.net.provider.ProviderId;
import java.lang.reflect.Field;
@@ -84,6 +95,17 @@
Link.Type.DIRECT, Link.State.ACTIVE);
}
+ /**
+ * Short-hand for creating a link.
+ *
+ * @param src the src of the link
+ * @param dst the dst of the link
+ * @return a link
+ */
+ public static Link link(ConnectPoint src, ConnectPoint dst) {
+ return new DefaultLink(PID, src, dst, Link.Type.DIRECT, Link.State.ACTIVE);
+ }
+
// Creates a path that leads through the given devices.
public static Path createPath(String... ids) {
List<Link> links = new ArrayList<>();
@@ -152,4 +174,88 @@
}
}
+ /**
+ * Builds an empty selector.
+ *
+ * @return the selector
+ */
+ public static TrafficSelector emptySelector() {
+ return DefaultTrafficSelector.emptySelector();
+ }
+
+ /**
+ * Builds a vlan selector.
+ *
+ * @return the selector
+ */
+ public static TrafficSelector vlanSelector(String vlanId) {
+ return DefaultTrafficSelector.builder()
+ .matchVlanId(VlanId.vlanId(vlanId))
+ .build();
+ }
+
+ /**
+ * Builds a mpls selector.
+ *
+ * @return the selector
+ */
+ public static TrafficSelector mplsSelector(String mplsLabel) {
+ return DefaultTrafficSelector.builder()
+ .matchMplsLabel(MplsLabel.mplsLabel(mplsLabel))
+ .build();
+ }
+
+ /**
+ * Builds an ip prefix dst selector.
+ *
+ * @return the selector
+ */
+ public static TrafficSelector ipPrefixDstSelector(String prefix) {
+ return DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf(prefix))
+ .build();
+ }
+
+ /**
+ * Builds an empty treatment.
+ *
+ * @return the treatment
+ */
+ public static TrafficTreatment emptyTreatment() {
+ return DefaultTrafficTreatment.emptyTreatment();
+ }
+
+ /**
+ * Builds a mac dst treatment.
+ *
+ * @return the treatment
+ */
+ public static TrafficTreatment macDstTreatment(String mac) {
+ return DefaultTrafficTreatment.builder()
+ .setEthDst(MacAddress.valueOf(mac))
+ .build();
+ }
+
+ /**
+ * Builds a list containing a vlan encapsulation constraint.
+ *
+ * @return the list of constraints
+ */
+ public static List<Constraint> vlanConstraint() {
+ return ImmutableList.of(
+ new EncapsulationConstraint(EncapsulationType.VLAN)
+ );
+ }
+
+ /**
+ * Builds a list containing a mpls encapsulation constraint.
+ *
+ * @return the list of constraints
+ */
+ public static List<Constraint> mplsConstraint() {
+ return ImmutableList.of(
+ new EncapsulationConstraint(EncapsulationType.MPLS)
+ );
+ }
+
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
index 50578de..38be5e4 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
@@ -170,7 +170,7 @@
}
private void changeLabelSelections() {
- PathCompiler.labelAllocator.setLabelSelection(labelSelection);
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(labelSelection);
}
}
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 7701f29..d5df116 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
@@ -16,12 +16,19 @@
package org.onosproject.net.intent.impl.compiler;
+import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Identifier;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
+import org.onosproject.net.EncapsulationType;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
import org.onosproject.net.FilteredConnectPoint;
@@ -31,6 +38,7 @@
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criteria;
import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.MplsCriterion;
import org.onosproject.net.flow.criteria.TunnelIdCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
@@ -54,27 +62,696 @@
import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
import org.onosproject.net.intent.IntentCompilationException;
import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.resource.impl.LabelAllocator;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.stream.Collectors;
import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_LABEL;
import static org.onosproject.net.flow.criteria.Criterion.Type.TUNNEL_ID;
import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
-
/**
* Shared APIs and implementations for Link Collection compilers.
*/
public class LinkCollectionCompiler<T> {
+ /**
+ * Reference to the label allocator.
+ */
+ static LabelAllocator labelAllocator;
+
+ /**
+ * The allowed tag criterions.
+ */
private static final Set<Criterion.Type> TAG_CRITERION_TYPES =
Sets.immutableEnumSet(VLAN_VID, MPLS_LABEL, TUNNEL_ID);
/**
- * Helper class to encapsulate treatment and selector.
+ * Error message for wrong egress scenario.
+ */
+ private static final String WRONG_EGRESS = "Egress points not equal to 1 " +
+ "and apply treatment at ingress, " +
+ "which treatments should I apply ???";
+
+ /**
+ * Error message for wrong ingress scenario.
+ */
+ private static final String WRONG_INGRESS = "Ingress points not equal to 1 " +
+ "and apply treatment at egress, " +
+ "how can I match in the core ???";
+
+ /**
+ * Error message for wrong encapsulation scenario.
+ */
+ private static final String WRONG_ENCAPSULATION = "Wrong scenario - 1 hop with " +
+ "encapsualtion";
+
+ /**
+ * Error message for unavailable labels.
+ */
+ private static final String NO_LABELS = "No available label for %s";
+
+ /**
+ * Error message for wrong encapsulation.
+ */
+ private static final String UNKNOWN_ENCAPSULATION = "Unknown encapsulation type";
+
+ /**
+ * Error message for unsupported L0 instructions.
+ */
+ private static final String UNSUPPORTED_L0 = "L0 not supported";
+
+ /**
+ * Error message for unsupported L1 instructions.
+ */
+ private static final String UNSUPPORTED_L1 = "L1 not supported";
+
+ /**
+ * Error message for unsupported eth subtype.
+ */
+ private static final String UNSUPPORTED_ETH_SUBTYPE = "Bad eth subtype";
+
+ /**
+ * Error message for unsupported pop action.
+ */
+ private static final String UNSUPPORTED_POP_ACTION = "Can't handle pop label";
+
+ /**
+ * Error message for unsupported L2 instructions.
+ */
+ private static final String UNSUPPORTED_L2 = "Unknown L2 Modification instruction";
+
+ /**
+ * Error message for unsupported IP subtype.
+ */
+ private static final String UNSUPPORTED_IP_SUBTYPE = "Bad ip subtype";
+
+ /**
+ * Error message for unsupported ARP.
+ */
+ private static final String UNSUPPORTED_ARP = "IPv6 not supported for ARP";
+
+ /**
+ * Error message for unsupported L3 instructions.
+ */
+ private static final String UNSUPPORTED_L3 = "Unknown L3 Modification instruction";
+
+ /**
+ * Error message for unsupported L4 subtype.
+ */
+ private static final String UNSUPPORTED_L4_SUBTYPE = "Unknown L4 subtype";
+
+ /**
+ * Error message for unsupported L4 instructions.
+ */
+ private static final String UNSUPPORTED_L4 = "Unknown L4 Modification instruction";
+
+ /**
+ * Error message for unsupported instructions.
+ */
+ private static final String UNSUPPORTED_INSTRUCTION = "Unknown instruction type";
+
+ /**
+ * Creates the flows representations. This default implementation does
+ * nothing. Subclasses should override this method to create their
+ * specific flows representations (flow rule, flow objective).
+ *
+ * @param intent the intent to compile
+ * @param deviceId the affected device
+ * @param inPorts the input ports
+ * @param outPorts the output ports
+ * @param labels the labels for the label switching hop by hop
+ * @return the list of flows representations
+ */
+ protected List<T> createRules(LinkCollectionIntent intent,
+ DeviceId deviceId,
+ Set<PortNumber> inPorts,
+ Set<PortNumber> outPorts,
+ Map<ConnectPoint, Identifier<?>> labels) {
+ return null;
+ }
+
+ /**
+ * Helper method to handle the different scenario (not encap, single hop, encap).
+ *
+ * @param encapConstraint the encapsulation constraint if it is present
+ * @param intent the link collection intent
+ * @param inPort the in port
+ * @param outPorts the out ports
+ * @param deviceId the current device
+ * @param labels the labels used by the encapsulation
+ * @return the forwarding instruction
+ */
+ protected ForwardingInstructions createForwardingInstruction(Optional<EncapsulationConstraint> encapConstraint,
+ LinkCollectionIntent intent,
+ PortNumber inPort,
+ Set<PortNumber> outPorts,
+ DeviceId deviceId,
+ Map<ConnectPoint, Identifier<?>> labels) {
+ ForwardingInstructions instructions = null;
+ /*
+ * If not encapsulation or single hop.
+ */
+ if (!encapConstraint.isPresent() || intent.links().isEmpty()) {
+ instructions = this.createForwardingInstructions(
+ intent,
+ inPort,
+ deviceId,
+ outPorts
+ );
+ /*
+ * If encapsulation is present. We retrieve the labels
+ * for this iteration;
+ */
+ } else {
+ Identifier<?> inLabel = labels.get(new ConnectPoint(deviceId, inPort));
+ Map<ConnectPoint, Identifier<?>> outLabels = Maps.newHashMap();
+ outPorts.forEach(outPort -> {
+ ConnectPoint key = new ConnectPoint(deviceId, outPort);
+ outLabels.put(key, labels.get(key));
+ });
+ instructions = this.createForwardingInstructions(
+ intent,
+ inPort,
+ inLabel,
+ deviceId,
+ outPorts,
+ outLabels,
+ encapConstraint.get().encapType()
+ );
+ }
+ return instructions;
+ }
+
+ /**
+ * Manages the Intents with a single ingress point (p2p, sp2mp)
+ * creating properly the selector builder and the treatment builder.
+ *
+ * @param selectorBuilder the selector builder to update
+ * @param treatmentBuilder the treatment builder to update
+ * @param intent the intent to compile
+ * @param deviceId the current device
+ * @param outPorts the output ports of this device
+ */
+ private void manageSpIntent(TrafficSelector.Builder selectorBuilder,
+ TrafficTreatment.Builder treatmentBuilder,
+ LinkCollectionIntent intent,
+ DeviceId deviceId,
+ Set<PortNumber> outPorts) {
+ /*
+ * Sanity check.
+ */
+ if (intent.filteredIngressPoints().size() != 1) {
+ throw new IntentCompilationException(WRONG_INGRESS);
+ }
+ /*
+ * For the p2p and sp2mp the transition initial state
+ * to final state is performed at the egress.
+ */
+ Optional<FilteredConnectPoint> filteredIngressPoint =
+ intent.filteredIngressPoints().stream().findFirst();
+ /*
+ * We build the final selector, adding the selector
+ * of the FIP to the Intent selector and potentially
+ * overriding its matches.
+ */
+ filteredIngressPoint.get()
+ .trafficSelector()
+ .criteria()
+ .forEach(selectorBuilder::add);
+ /*
+ * In this scenario, potentially we can have several output
+ * ports.
+ */
+ for (PortNumber outPort : outPorts) {
+ Optional<FilteredConnectPoint> filteredEgressPoint =
+ getFilteredConnectPointFromIntent(deviceId, outPort, intent);
+ /*
+ * If we are at the egress, we have to transit to the final
+ * state.
+ */
+ if (filteredEgressPoint.isPresent()) {
+ /*
+ * We add the Intent treatment.
+ */
+ intent.treatment().allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ /*
+ * We generate the transition FIP->FEP.
+ */
+ TrafficTreatment forwardingTreatment =
+ forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
+ filteredEgressPoint.get().trafficSelector(),
+ getEthType(intent.selector()));
+ /*
+ * We add the instruction necessary to the transition.
+ * Potentially we override the intent treatment.
+ */
+ forwardingTreatment.allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ }
+ /*
+ * Finally we set the output action.
+ */
+ treatmentBuilder.setOutput(outPort);
+ }
+ }
+
+ /**
+ * Manages the Intents with multiple ingress points creating properly
+ * the selector builder and the treatment builder.
+ *
+ * @param selectorBuilder the selector builder to update
+ * @param treatmentBuilder the treatment builder to update
+ * @param intent the intent to compile
+ * @param inPort the input port of the current device
+ * @param deviceId the current device
+ * @param outPorts the output ports of this device
+ */
+ private void manageMpIntent(TrafficSelector.Builder selectorBuilder,
+ TrafficTreatment.Builder treatmentBuilder,
+ LinkCollectionIntent intent,
+ PortNumber inPort,
+ DeviceId deviceId,
+ Set<PortNumber> outPorts) {
+ /*
+ * Sanity check
+ */
+ if (intent.filteredEgressPoints().size() != 1) {
+ throw new IntentCompilationException(WRONG_EGRESS);
+ }
+ /*
+ * We try to understand if the device is one of the ingress points.
+ */
+ Optional<FilteredConnectPoint> filteredIngressPoint =
+ getFilteredConnectPointFromIntent(deviceId, inPort, intent);
+ /*
+ * We retrieve from the Intent the unique egress points.
+ */
+ Optional<FilteredConnectPoint> filteredEgressPoint =
+ intent.filteredEgressPoints().stream().findFirst();
+ /*
+ * We check if the device is the ingress device
+ */
+ if (filteredIngressPoint.isPresent()) {
+ /*
+ * We are at ingress, so basically what we have to do is this:
+ * apply a set of operations (treatment, FEP) in order to have
+ * a transition from the initial state to the final state.
+ *
+ * We initialize the treatment with the Intent treatment
+ */
+ intent.treatment().allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ /*
+ * We build the final selector, adding the selector
+ * of the FIP to the Intent selector and potentially
+ * overriding its matches.
+ */
+ filteredIngressPoint.get()
+ .trafficSelector()
+ .criteria()
+ .forEach(selectorBuilder::add);
+ /*
+ * We define the transition FIP->FEP, basically
+ * the set of the operations we need for reaching
+ * the final state.
+ */
+ TrafficTreatment forwardingTreatment =
+ forwardingTreatment(filteredIngressPoint.get().trafficSelector(),
+ filteredEgressPoint.get().trafficSelector(),
+ getEthType(intent.selector()));
+ /*
+ * We add to the treatment the actions necessary for the
+ * transition, potentially overriding the treatment of the
+ * Intent. The Intent treatment has always a low priority
+ * in respect of the FEP.
+ */
+ forwardingTreatment.allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ } else {
+ /*
+ * We are in the core or in the egress switch.
+ * The packets are in their final state. We need
+ * to match against this final state.
+ *
+ * we derive the final state defined by the intent
+ * treatment.
+ */
+ updateBuilder(selectorBuilder, intent.treatment());
+ /*
+ * We derive the final state defined by the unique
+ * FEP. We merge the two states.
+ */
+ filteredEgressPoint.get()
+ .trafficSelector()
+ .criteria()
+ .forEach(selectorBuilder::add);
+ }
+ /*
+ * Finally we set the output action.
+ */
+ outPorts.forEach(treatmentBuilder::setOutput);
+ }
+
+ /**
+ * Computes treatment and selector which will be used
+ * in the flow representation (Rule, Objective).
+ *
+ * @param intent the intent to compile
+ * @param inPort the input port of this device
+ * @param deviceId the current device
+ * @param outPorts the output ports of this device
+ * @return the forwarding instruction object which encapsulates treatment and selector
+ */
+ protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
+ PortNumber inPort,
+ DeviceId deviceId,
+ Set<PortNumber> outPorts) {
+
+ /*
+ * We build an empty treatment and we initialize the selector with
+ * the intent selector.
+ */
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
+ .builder();
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector
+ .builder(intent.selector())
+ .matchInPort(inPort);
+
+ if (!intent.applyTreatmentOnEgress()) {
+ manageMpIntent(selectorBuilder,
+ treatmentBuilder,
+ intent,
+ inPort,
+ deviceId,
+ outPorts
+ );
+ } else {
+ manageSpIntent(selectorBuilder,
+ treatmentBuilder,
+ intent,
+ deviceId,
+ outPorts
+ );
+ }
+ /*
+ * We return selector and treatment necessary to build the flow rule
+ * or the flow objective.
+ */
+ return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
+ }
+
+ /**
+ * Manages the ingress of the Intents (p2p, sp2mp, mp2sp) with encapsulation.
+ *
+ * @param selectorBuilder the selector builder to update
+ * @param treatmentBuilder the treatment builder to update
+ * @param intent the intent to compile
+ * @param inPort the input port of this device
+ * @param deviceId the current device
+ * @param outPorts the output ports of this device
+ * @param outLabels the labels associated to the output port
+ * @param type the encapsulation type
+ */
+ private void manageEncapAtIngress(TrafficSelector.Builder selectorBuilder,
+ TrafficTreatment.Builder treatmentBuilder,
+ LinkCollectionIntent intent,
+ PortNumber inPort,
+ DeviceId deviceId,
+ Set<PortNumber> outPorts,
+ Map<ConnectPoint, Identifier<?>> outLabels,
+ EncapsulationType type) {
+
+ Optional<FilteredConnectPoint> filteredIngressPoint =
+ getFilteredConnectPointFromIntent(deviceId, inPort, intent);
+ /*
+ * We fill the selector builder with the intent selector.
+ */
+ intent.selector().criteria().forEach(selectorBuilder::add);
+ /*
+ * We build the final selector, adding the selector
+ * of the FIP to the Intent selector and potentially
+ * overriding its matches.
+ */
+ filteredIngressPoint.get()
+ .trafficSelector()
+ .criteria()
+ .forEach(selectorBuilder::add);
+ /*
+ * In this scenario, we can have several output ports.
+ */
+ 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);
+ });
+
+ }
+
+ /**
+ * Manages the core and transit of the Intents (p2p, sp2mp, mp2sp)
+ * with encapsulation.
+ *
+ * @param selectorBuilder the selector builder to update
+ * @param treatmentBuilder the treatment builder to update
+ * @param intent the intent to compile
+ * @param inPort the input port of this device
+ * @param inLabel the label associated to the input port
+ * @param deviceId the current device
+ * @param outPorts the output ports of this device
+ * @param outLabels the labels associated to the output port
+ * @param type the encapsulation type
+ */
+ private void manageEncapAtCoreAndEgress(TrafficSelector.Builder selectorBuilder,
+ TrafficTreatment.Builder treatmentBuilder,
+ LinkCollectionIntent intent,
+ PortNumber inPort,
+ Identifier<?> inLabel,
+ DeviceId deviceId,
+ Set<PortNumber> outPorts,
+ Map<ConnectPoint, Identifier<?>> outLabels,
+ EncapsulationType type) {
+
+ /*
+ * If there are not labels, we cannot handle.
+ */
+ ConnectPoint inCp = new ConnectPoint(deviceId, inPort);
+ if (inLabel == null) {
+ throw new IntentCompilationException(String.format(NO_LABELS, inCp));
+ }
+ /*
+ * In the core and at egress we match using encapsulation.
+ */
+ updateSelectorFromEncapsulation(
+ selectorBuilder,
+ type,
+ inLabel
+ );
+ /*
+ * We need to order the actions. First the actions
+ * related to the not-egress points.
+ */
+ outPorts.forEach(outPort -> {
+ 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);
+ }
+
+ });
+ /*
+ * In this case, we have to transit to the final
+ * state.
+ */
+ outPorts.forEach(outPort -> {
+ Optional<FilteredConnectPoint> filteredEgressPoint =
+ getFilteredConnectPointFromIntent(deviceId, outPort, intent);
+ if (filteredEgressPoint.isPresent()) {
+ /*
+ * We add the Intent treatment to the final
+ * treatment.
+ */
+ intent.treatment().allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ /*
+ * We generate the transition FIP->FEP.
+ */
+ TrafficTreatment forwardingTreatment =
+ forwardingTreatment(selectorBuilder.build(),
+ filteredEgressPoint.get().trafficSelector(),
+ getEthType(intent.selector()));
+ /*
+ * We add the instruction necessary to the transition.
+ * Potentially we override the intent treatment.
+ */
+ forwardingTreatment.allInstructions().stream()
+ .filter(inst -> inst.type() != Instruction.Type.NOACTION)
+ .forEach(treatmentBuilder::add);
+ /*
+ * Finally we set the output action.
+ */
+ treatmentBuilder.setOutput(outPort);
+ }
+ });
+
+ }
+
+ /**
+ * Computes treatment and selector which will be used
+ * in the flow representation (Rule, Objective).
+ *
+ * @param intent the intent to compile
+ * @param inPort the input port of this device
+ * @param inLabel the label associated to the input port
+ * @param deviceId the current device
+ * @param outPorts the output ports of this device
+ * @param outLabels the labels associated to the output port
+ * @param type the encapsulation type
+ * @return the forwarding instruction object which encapsulates treatment and selector
+ */
+ protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
+ PortNumber inPort,
+ Identifier<?> inLabel,
+ DeviceId deviceId,
+ Set<PortNumber> outPorts,
+ Map<ConnectPoint, Identifier<?>> outLabels,
+ EncapsulationType type) {
+ /*
+ * We build an empty treatment and an empty selector.
+ */
+ TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
+ TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+ selectorBuilder.matchInPort(inPort);
+ Optional<FilteredConnectPoint> filteredIngressPoint =
+ getFilteredConnectPointFromIntent(deviceId, inPort, intent);
+
+ if (filteredIngressPoint.isPresent()) {
+ manageEncapAtIngress(selectorBuilder,
+ treatmentBuilder,
+ intent,
+ inPort,
+ deviceId,
+ outPorts,
+ outLabels,
+ type
+ );
+ } else {
+ manageEncapAtCoreAndEgress(selectorBuilder,
+ treatmentBuilder,
+ intent,
+ inPort,
+ inLabel,
+ deviceId,
+ outPorts,
+ outLabels,
+ type);
+ }
+ /*
+ * We return selector and treatment necessary to build the flow rule
+ * or the flow objective.
+ */
+ return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
+ }
+
+ /**
+ * Helper class to encapsulate treatment and selector
+ * in an unique abstraction.
*/
protected class ForwardingInstructions {
@@ -100,7 +777,8 @@
}
/**
- * Helper method to compute input and output ports.
+ * Helper method to compute input and output ports
+ * for each device crossed in the path.
*
* @param intent the related intents
* @param inputPorts the input ports to compute
@@ -122,169 +800,25 @@
for (ConnectPoint egressPoint : intent.egressPoints()) {
outputPorts.put(egressPoint.deviceId(), egressPoint.port());
}
- }
-
- /**
- * Gets ingress and egress port number of specific device.
- *
- * @param intent the related
- * @param deviceId device Id
- * @param ingressPorts the ingress ports to compute
- * @param egressPorts the egress ports to compute
- */
- protected void computePorts(LinkCollectionIntent intent,
- DeviceId deviceId,
- Set<PortNumber> ingressPorts,
- Set<PortNumber> egressPorts) {
-
- if (!intent.applyTreatmentOnEgress()) {
- ingressPorts.addAll(intent.ingressPoints().stream()
- .filter(point -> point.deviceId().equals(deviceId))
- .map(ConnectPoint::port)
- .collect(Collectors.toSet()));
- } else {
- egressPorts.addAll(intent.egressPoints().stream()
- .filter(point -> point.deviceId().equals(deviceId))
- .map(ConnectPoint::port)
- .collect(Collectors.toSet()));
- }
}
/**
- * Creates the flows representations.
+ * Retrieves the encapsulation constraint from the link collection intent.
*
- * @param intent the intent to compile
- * @param deviceId the affected device
- * @param inPorts the input ports
- * @param outPorts the output ports
- * @return the list of flows representations
+ * @param intent the intent to analyze
+ * @return the encapsulation constraint
*/
- protected List<T> createRules(LinkCollectionIntent intent, DeviceId deviceId,
- Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
- return null;
+ protected Optional<EncapsulationConstraint> getIntentEncapConstraint(LinkCollectionIntent intent) {
+ return intent.constraints().stream()
+ .filter(constraint -> constraint instanceof EncapsulationConstraint)
+ .map(x -> (EncapsulationConstraint) x).findAny();
}
/**
- * Computes treatment and selector which will be used
- * in the flow representation (Rule, Objective).
- *
- * @param intent the intent to compile
- * @param inPort the input port of this device
- * @param deviceId the current device
- * @param outPorts the output ports of this device
- * @param ingressPorts intent ingress ports of this device
- * @param egressPorts intent egress ports of this device
- * @return the forwarding instruction object which encapsulates treatment and selector
- */
- protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
- PortNumber inPort,
- DeviceId deviceId,
- Set<PortNumber> outPorts,
- Set<PortNumber> ingressPorts,
- Set<PortNumber> egressPorts) {
-
- TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
- selectorBuilder.matchInPort(inPort);
-
- if (!intent.applyTreatmentOnEgress()) {
- // FIXME: currently, we assume this intent is compile from mp2sp intent
- Optional<FilteredConnectPoint> filteredIngressPoint =
- getFilteredConnectPointFromIntent(deviceId, inPort, intent);
- Optional<FilteredConnectPoint> filteredEgressPoint =
- intent.filteredEgressPoints().stream().findFirst();
-
- if (filteredIngressPoint.isPresent()) {
- // Ingress device
- intent.treatment().allInstructions().stream()
- .filter(inst -> inst.type() != Instruction.Type.NOACTION)
- .forEach(treatmentBuilder::add);
-
- if (filteredEgressPoint.isPresent()) {
- // Apply selector from ingress point
- filteredIngressPoint.get()
- .trafficSelector()
- .criteria()
- .forEach(selectorBuilder::add);
-
- TrafficTreatment forwardingTreatment =
- forwardingTreatment(filteredIngressPoint.get(),
- filteredEgressPoint.get());
-
- forwardingTreatment.allInstructions().stream()
- .filter(inst -> inst.type() != Instruction.Type.NOACTION)
- .forEach(treatmentBuilder::add);
- } else {
- throw new IntentCompilationException("Can't find filtered connection point");
- }
-
- } else {
- // Not ingress device, won't apply treatments.
- // Use selector by treatment from intent.
- updateBuilder(selectorBuilder, intent.treatment());
-
- // Selector should be overridden by selector from connect point.
- if (filteredEgressPoint.isPresent()) {
- filteredEgressPoint.get()
- .trafficSelector()
- .criteria()
- .forEach(selectorBuilder::add);
- }
-
- }
-
- outPorts.forEach(treatmentBuilder::setOutput);
-
- } else {
- // FIXME: currently, we assume this intent is compile from sp2mp intent
- Optional<FilteredConnectPoint> filteredIngressPoint =
- intent.filteredIngressPoints().stream().findFirst();
-
- if (filteredIngressPoint.isPresent()) {
- // Apply selector from ingress point
- filteredIngressPoint.get()
- .trafficSelector()
- .criteria()
- .forEach(selectorBuilder::add);
- } else {
- throw new IntentCompilationException(
- "Filtered connection point for ingress" +
- "point does not exist");
- }
-
- for (PortNumber outPort : outPorts) {
- Optional<FilteredConnectPoint> filteredEgressPoint =
- getFilteredConnectPointFromIntent(deviceId, outPort, intent);
-
- if (filteredEgressPoint.isPresent()) {
- // Egress port, apply treatment + forwarding treatment
- intent.treatment().allInstructions().stream()
- .filter(inst -> inst.type() != Instruction.Type.NOACTION)
- .forEach(treatmentBuilder::add);
-
- TrafficTreatment forwardingTreatment =
- forwardingTreatment(filteredIngressPoint.get(),
- filteredEgressPoint.get());
- forwardingTreatment.allInstructions().stream()
- .filter(inst -> inst.type() != Instruction.Type.NOACTION)
- .forEach(treatmentBuilder::add);
- }
-
- treatmentBuilder.setOutput(outPort);
-
- }
-
- }
-
-
- return new ForwardingInstructions(treatmentBuilder.build(), selectorBuilder.build());
-
- }
-
- /**
* Get FilteredConnectPoint from LinkCollectionIntent.
+ *
* @param deviceId device Id for connect point
* @param portNumber port number
* @param intent source intent
@@ -320,15 +854,17 @@
* Compares tag type between ingress and egress point and generate
* treatment for egress point of intent.
*
- * @param ingress ingress point for the intent
- * @param egress egress point for the intent
+ * @param ingress ingress selector for the intent
+ * @param egress egress selector for the intent
+ * @param ethType the ethertype to use in mpls_pop
* @return Builder of TrafficTreatment
*/
- private TrafficTreatment forwardingTreatment(FilteredConnectPoint ingress,
- FilteredConnectPoint egress) {
+ private TrafficTreatment forwardingTreatment(TrafficSelector ingress,
+ TrafficSelector egress,
+ EthType ethType) {
- if (ingress.trafficSelector().equals(egress.trafficSelector())) {
+ if (ingress.equals(egress)) {
return DefaultTrafficTreatment.emptyTreatment();
}
@@ -338,8 +874,8 @@
* "null" means there is no tag for the port
* Tag criterion will be null if port is normal connection point
*/
- Criterion ingressTagCriterion = getTagCriterion(ingress.trafficSelector());
- Criterion egressTagCriterion = getTagCriterion(egress.trafficSelector());
+ Criterion ingressTagCriterion = getTagCriterion(ingress);
+ Criterion egressTagCriterion = getTagCriterion(egress);
if (ingressTagCriterion.type() != egressTagCriterion.type()) {
@@ -353,11 +889,14 @@
case VLAN_VID:
builder.popVlan();
break;
+
case MPLS_LABEL:
- builder.popMpls();
+ builder.popMpls(ethType);
break;
+
default:
break;
+
}
/*
@@ -367,11 +906,14 @@
case VLAN_VID:
builder.pushVlan();
break;
+
case MPLS_LABEL:
builder.pushMpls();
break;
+
default:
break;
+
}
}
@@ -380,16 +922,20 @@
VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) egressTagCriterion;
builder.setVlanId(vlanIdCriterion.vlanId());
break;
+
case MPLS_LABEL:
MplsCriterion mplsCriterion = (MplsCriterion) egressTagCriterion;
builder.setMpls(mplsCriterion.label());
break;
+
case TUNNEL_ID:
TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) egressTagCriterion;
builder.setTunnelId(tunnelIdCriterion.tunnelId());
break;
+
default:
break;
+
}
return builder.build();
@@ -402,7 +948,7 @@
* @param l0instruction the l0 instruction to use
*/
private void updateBuilder(TrafficSelector.Builder builder, L0ModificationInstruction l0instruction) {
- throw new IntentCompilationException("L0 not supported");
+ throw new IntentCompilationException(UNSUPPORTED_L0);
}
/**
@@ -412,7 +958,7 @@
* @param l1instruction the l1 instruction to use
*/
private void updateBuilder(TrafficSelector.Builder builder, L1ModificationInstruction l1instruction) {
- throw new IntentCompilationException("L1 not supported");
+ throw new IntentCompilationException(UNSUPPORTED_L1);
}
/**
@@ -430,49 +976,59 @@
case ETH_SRC:
builder.matchEthSrc(ethInstr.mac());
break;
+
case ETH_DST:
builder.matchEthDst(ethInstr.mac());
break;
+
default:
- throw new IntentCompilationException("Bad eth subtype");
+ throw new IntentCompilationException(UNSUPPORTED_ETH_SUBTYPE);
}
break;
+
case VLAN_ID:
ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2instruction;
builder.matchVlanId(vlanIdInstr.vlanId());
break;
+
case VLAN_PUSH:
//FIXME
break;
+
case VLAN_POP:
//TODO how do we handle dropped label? remove the selector?
- throw new IntentCompilationException("Can't handle pop label");
+ throw new IntentCompilationException(UNSUPPORTED_POP_ACTION);
case VLAN_PCP:
ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2instruction;
builder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
break;
+
case MPLS_LABEL:
case MPLS_PUSH:
//FIXME
ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2instruction;
builder.matchMplsLabel(mplsInstr.label());
break;
+
case MPLS_POP:
//TODO how do we handle dropped label? remove the selector?
- throw new IntentCompilationException("Can't handle pop label");
+ throw new IntentCompilationException(UNSUPPORTED_POP_ACTION);
case DEC_MPLS_TTL:
// no-op
break;
+
case MPLS_BOS:
ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2instruction;
builder.matchMplsBos(mplsBosInstr.mplsBos());
break;
+
case TUNNEL_ID:
ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2instruction;
builder.matchTunnelId(tunInstr.tunnelId());
break;
+
default:
- throw new IntentCompilationException("Unknown L2 Modification instruction");
+ throw new IntentCompilationException(UNSUPPORTED_L2);
}
}
@@ -497,51 +1053,63 @@
case IPV4_SRC:
builder.matchIPSrc(prefix);
break;
+
case IPV4_DST:
builder.matchIPSrc(prefix);
break;
+
case IPV6_SRC:
builder.matchIPv6Src(prefix);
break;
+
case IPV6_DST:
builder.matchIPv6Dst(prefix);
break;
+
default:
- throw new IntentCompilationException("Bad type for IP instruction");
+ throw new IntentCompilationException(UNSUPPORTED_IP_SUBTYPE);
}
break;
+
case IPV6_FLABEL:
ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3instruction;
builder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
break;
+
case DEC_TTL:
// no-op
break;
+
case TTL_OUT:
// no-op
break;
+
case TTL_IN:
// no-op
break;
+
case ARP_SPA:
ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3instruction;
if (arpIpInstr.ip().isIp4()) {
builder.matchArpSpa((Ip4Address) arpIpInstr.ip());
} else {
- throw new IntentCompilationException("IPv6 not supported for ARP");
+ throw new IntentCompilationException(UNSUPPORTED_ARP);
}
break;
+
case ARP_SHA:
ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3instruction;
builder.matchArpSha(arpEthInstr.mac());
break;
+
case ARP_OP:
ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3instruction;
//FIXME is the long to int cast safe?
builder.matchArpOp((int) arpOpInstr.op());
break;
+
default:
- throw new IntentCompilationException("Unknown L3 Modification instruction");
+ throw new IntentCompilationException(UNSUPPORTED_L3);
}
}
@@ -559,20 +1127,24 @@
case TCP_SRC:
builder.matchTcpSrc(l4mod.port());
break;
+
case TCP_DST:
builder.matchTcpDst(l4mod.port());
break;
+
case UDP_SRC:
builder.matchUdpSrc(l4mod.port());
break;
+
case UDP_DST:
builder.matchUdpDst(l4mod.port());
break;
+
default:
- throw new IntentCompilationException("Unknown L4 Modification instruction");
+ throw new IntentCompilationException(UNSUPPORTED_L4_SUBTYPE);
}
} else {
- throw new IntentCompilationException("Unknown L4 Modification instruction");
+ throw new IntentCompilationException(UNSUPPORTED_L4);
}
}
@@ -589,18 +1161,23 @@
case L0MODIFICATION:
updateBuilder(builder, (L0ModificationInstruction) instruction);
break;
+
case L1MODIFICATION:
updateBuilder(builder, (L1ModificationInstruction) instruction);
break;
+
case L2MODIFICATION:
updateBuilder(builder, (L2ModificationInstruction) instruction);
break;
+
case L3MODIFICATION:
updateBuilder(builder, (L3ModificationInstruction) instruction);
break;
+
case L4MODIFICATION:
updateBuilder(builder, (L4ModificationInstruction) instruction);
break;
+
case NOACTION:
case OUTPUT:
case GROUP:
@@ -611,11 +1188,57 @@
case EXTENSION: // TODO is extension no-op or unsupported?
// Nothing to do
break;
+
default:
- throw new IntentCompilationException("Unknown instruction type");
+ throw new IntentCompilationException(UNSUPPORTED_INSTRUCTION);
}
});
}
+ /**
+ * The method generates a selector starting from
+ * the encapsulation information (type and label to match).
+ *
+ * @param selectorBuilder the builder to update
+ * @param type the type of encapsulation
+ * @param identifier the label to match
+ */
+ private void updateSelectorFromEncapsulation(TrafficSelector.Builder selectorBuilder,
+ EncapsulationType type,
+ Identifier<?> identifier) {
+ switch (type) {
+ case MPLS:
+ MplsLabel label = (MplsLabel) identifier;
+ selectorBuilder.matchMplsLabel(label);
+ selectorBuilder.matchEthType(Ethernet.MPLS_UNICAST);
+ break;
+
+ case VLAN:
+ VlanId id = (VlanId) identifier;
+ selectorBuilder.matchVlanId(id);
+ break;
+
+ default:
+ throw new IntentCompilationException(UNKNOWN_ENCAPSULATION);
+ }
+ }
+
+ /**
+ * Helper function to define the match on the ethertype.
+ * If the selector define an ethertype we will use it,
+ * otherwise IPv4 will be used by default.
+ *
+ * @param selector the traffic selector
+ * @return the ethertype we should match
+ */
+ private EthType getEthType(TrafficSelector selector) {
+ Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
+ if (c != null && c instanceof EthTypeCriterion) {
+ EthTypeCriterion ethertype = (EthTypeCriterion) c;
+ return ethertype.ethType();
+ }
+ return EthType.EtherType.IPV4.ethType();
+ }
+
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
index 1f22429..e464e99 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
@@ -16,16 +16,17 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.util.Identifier;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultFlowRule;
@@ -34,12 +35,17 @@
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.resource.impl.LabelAllocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.Set;
/**
@@ -59,12 +65,18 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ResourceService resourceService;
+
private ApplicationId appId;
@Activate
public void activate() {
appId = coreService.registerApplication("org.onosproject.net.intent");
registrator.registerCompiler(LinkCollectionIntent.class, this, false);
+ if (labelAllocator == null) {
+ labelAllocator = new LabelAllocator(resourceService);
+ }
}
@Deactivate
@@ -77,36 +89,55 @@
SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
+ Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
+
+ Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
computePorts(intent, inputPorts, outputPorts);
+ if (encapConstraint.isPresent()) {
+ labels = labelAllocator.assignLabelToPorts(intent.links(),
+ intent.id(),
+ encapConstraint.get().encapType());
+ }
+
List<FlowRule> rules = new ArrayList<>();
for (DeviceId deviceId: outputPorts.keySet()) {
- rules.addAll(createRules(intent, deviceId, inputPorts.get(deviceId), outputPorts.get(deviceId)));
+ rules.addAll(createRules(
+ intent,
+ deviceId,
+ inputPorts.get(deviceId),
+ outputPorts.get(deviceId),
+ labels)
+ );
}
return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
}
@Override
- protected List<FlowRule> createRules(LinkCollectionIntent intent, DeviceId deviceId,
- Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
-
- Set<PortNumber> ingressPorts = Sets.newHashSet();
- Set<PortNumber> egressPorts = Sets.newHashSet();
-
- computePorts(intent, deviceId, ingressPorts, egressPorts);
+ protected List<FlowRule> createRules(LinkCollectionIntent intent,
+ DeviceId deviceId,
+ Set<PortNumber> inPorts,
+ Set<PortNumber> outPorts,
+ Map<ConnectPoint, Identifier<?>> labels) {
List<FlowRule> rules = new ArrayList<>(inPorts.size());
- Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
- Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
+ /*
+ * Looking for the encapsulation constraint
+ */
+ Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
inPorts.forEach(inport -> {
- ForwardingInstructions instructions = this.createForwardingInstructions(intent,
- inport,
- deviceId,
- outPorts,
- copyIngressPorts,
- copyEgressPorts);
+
+ ForwardingInstructions instructions = this.createForwardingInstruction(
+ encapConstraint,
+ intent,
+ inport,
+ outPorts,
+ deviceId,
+ labels
+ );
+
FlowRule rule = DefaultFlowRule.builder()
.forDevice(deviceId)
.withSelector(instructions.selector())
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
index 0d6ad0a..0a15097 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
@@ -16,16 +16,17 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.SetMultimap;
-import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.util.Identifier;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flowobjective.DefaultForwardingObjective;
@@ -38,10 +39,15 @@
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.resource.impl.LabelAllocator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
+import java.util.Optional;
import java.util.Set;
/**
@@ -61,12 +67,19 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected ResourceService resourceService;
+
private ApplicationId appId;
@Activate
public void activate() {
appId = coreService.registerApplication("org.onosproject.net.intent");
registrator.registerCompiler(LinkCollectionIntent.class, this, true);
+ if (labelAllocator == null) {
+ labelAllocator = new LabelAllocator(resourceService);
+ }
+
}
@Deactivate
@@ -79,9 +92,18 @@
SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
+ Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
+
+ Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
computePorts(intent, inputPorts, outputPorts);
+ if (encapConstraint.isPresent()) {
+ labels = labelAllocator.assignLabelToPorts(intent.links(),
+ intent.id(),
+ encapConstraint.get().encapType());
+ }
+
List<Objective> objectives = new ArrayList<>();
List<DeviceId> devices = new ArrayList<>();
for (DeviceId deviceId: outputPorts.keys()) {
@@ -89,7 +111,8 @@
createRules(intent,
deviceId,
inputPorts.get(deviceId),
- outputPorts.get(deviceId));
+ outputPorts.get(deviceId),
+ labels);
deviceObjectives.forEach(objective -> {
objectives.add(objective);
devices.add(deviceId);
@@ -100,25 +123,29 @@
}
@Override
- protected List<Objective> createRules(LinkCollectionIntent intent, DeviceId deviceId,
- Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
-
- Set<PortNumber> ingressPorts = Sets.newHashSet();
- Set<PortNumber> egressPorts = Sets.newHashSet();
-
- computePorts(intent, deviceId, ingressPorts, egressPorts);
+ protected List<Objective> createRules(LinkCollectionIntent intent,
+ DeviceId deviceId,
+ Set<PortNumber> inPorts,
+ Set<PortNumber> outPorts,
+ Map<ConnectPoint, Identifier<?>> labels) {
List<Objective> objectives = new ArrayList<>(inPorts.size());
- Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
- Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
+
+ /*
+ * Looking for the encapsulation constraint
+ */
+ Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
inPorts.forEach(inport -> {
- ForwardingInstructions instructions = this.createForwardingInstructions(intent,
- inport,
- deviceId,
- outPorts,
- copyIngressPorts,
- copyEgressPorts);
+
+ ForwardingInstructions instructions = this.createForwardingInstruction(
+ encapConstraint,
+ intent,
+ inport,
+ outPorts,
+ deviceId,
+ labels
+ );
NextObjective nextObjective = DefaultNextObjective.builder()
.withId(flowObjectiveService.allocateNextId())
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java
new file mode 100644
index 0000000..9a8324c
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.net.intent.impl.compiler;
+
+import com.google.common.collect.ImmutableSet;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.MockIdGenerator;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.onosproject.net.NetTestTools.*;
+import static org.onosproject.net.NetTestTools.macDstTreatment;
+
+/**
+ * Abstract class to hold the common variables and pieces
+ * of code.
+ */
+class AbstractLinkCollectionTest {
+
+ static final String LABEL_SELECTION = "FIRST_FIT";
+ static final String LABEL = "1";
+
+ final ApplicationId appId = new TestApplicationId("test");
+
+ final ConnectPoint d2p0 = connectPoint("s2", 0);
+ final ConnectPoint d2p1 = connectPoint("s2", 1);
+ ConnectPoint d2p10 = connectPoint("s2", 10);
+
+ final ConnectPoint d3p0 = connectPoint("s3", 0);
+ final ConnectPoint d3p1 = connectPoint("s3", 1);
+ final ConnectPoint d3p10 = connectPoint("s3", 10);
+
+ final DeviceId of1Id = DeviceId.deviceId("of:of1");
+ final DeviceId of2Id = DeviceId.deviceId("of:of2");
+ final DeviceId of3Id = DeviceId.deviceId("of:of3");
+ final DeviceId of4Id = DeviceId.deviceId("of:of4");
+
+ final ConnectPoint of1p1 = connectPoint("of1", 1);
+ final ConnectPoint of1p2 = connectPoint("of1", 2);
+ final ConnectPoint of2p1 = connectPoint("of2", 1);
+ final ConnectPoint of2p2 = connectPoint("of2", 2);
+ final ConnectPoint of2p3 = connectPoint("of2", 3);
+ final ConnectPoint of3p1 = connectPoint("of3", 1);
+ final ConnectPoint of3p2 = connectPoint("of3", 2);
+ final ConnectPoint of4p1 = connectPoint("of4", 1);
+ final ConnectPoint of4p2 = connectPoint("of4", 2);
+
+ final ConnectPoint d1p0 = connectPoint("s1", 0);
+ final ConnectPoint d1p1 = connectPoint("s1", 1);
+ final ConnectPoint d1p10 = connectPoint("s1", 10);
+ final ConnectPoint d1p11 = connectPoint("s1", 11);
+
+ final Set<Link> links = ImmutableSet.of(
+ link(d1p1, d2p0),
+ link(d2p1, d3p1),
+ link(d1p1, d3p1)
+ );
+
+ final Set<Link> linksForMp2Sp = ImmutableSet.of(
+ link(d1p0, d2p0),
+ link(d2p1, d3p0)
+ );
+
+
+
+ final Set<Link> linksForSp2Mp = ImmutableSet.of(
+ link(d3p0, d2p1),
+ link(d2p0, d1p0)
+ );
+
+ final TrafficTreatment treatment = emptyTreatment();
+
+ final TrafficSelector selector = emptySelector();
+ final TrafficSelector vlan69Selector = vlanSelector("69");
+ final TrafficSelector vlan100Selector = vlanSelector("100");
+ final TrafficSelector vlan200Selector = vlanSelector("200");
+ final TrafficSelector vlan300Selector = vlanSelector("300");
+ final TrafficSelector mpls69Selector = mplsSelector("69");
+ final TrafficSelector mpls80Selector = mplsSelector("80");
+ final TrafficSelector mpls100Selector = mplsSelector("100");
+ final TrafficSelector mpls200Selector = mplsSelector("200");
+ final TrafficSelector ipPrefixSelector = ipPrefixDstSelector("192.168.100.0/24");
+ final TrafficTreatment ethDstTreatment = macDstTreatment("C0:FF:EE:C0:FF:EE");
+
+ final List<Constraint> constraintsForVlan = vlanConstraint();
+ final List<Constraint> constraintsForMPLS = mplsConstraint();
+
+ CoreService coreService;
+ IntentExtensionService intentExtensionService;
+ IntentConfigurableRegistrator registrator;
+ IdGenerator idGenerator = new MockIdGenerator();
+
+ LinkCollectionIntent intent;
+
+ LinkCollectionIntentCompiler sut;
+
+ List<FlowRule> getFlowRulesByDevice(DeviceId deviceId, Collection<FlowRule> flowRules) {
+ return flowRules.stream()
+ .filter(fr -> fr.deviceId().equals(deviceId))
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionEncapIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionEncapIntentCompilerTest.java
new file mode 100644
index 0000000..588880a
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionEncapIntentCompilerTest.java
@@ -0,0 +1,1354 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * 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.net.intent.impl.compiler;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.criteria.MplsCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.resource.MockResourceService;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.core.Is.is;
+import static org.onlab.packet.EthType.EtherType.IPV4;
+import static org.onosproject.net.NetTestTools.*;
+import static org.onosproject.net.flow.criteria.Criterion.Type.*;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+
+/**
+ * This set of tests are meant to test the encapsulation
+ * in the LinkCollectionIntent.
+ */
+public class LinkCollectionEncapIntentCompilerTest extends AbstractLinkCollectionTest {
+
+ @Before
+ public void setUp() {
+ sut = new LinkCollectionIntentCompiler();
+ coreService = createMock(CoreService.class);
+ expect(coreService.registerApplication("org.onosproject.net.intent"))
+ .andReturn(appId);
+ sut.coreService = coreService;
+
+ Intent.bindIdGenerator(idGenerator);
+
+ intentExtensionService = createMock(IntentExtensionService.class);
+ intentExtensionService.registerCompiler(LinkCollectionIntent.class, sut);
+ intentExtensionService.unregisterCompiler(LinkCollectionIntent.class);
+
+ registrator = new IntentConfigurableRegistrator();
+ registrator.extensionService = intentExtensionService;
+ registrator.cfgService = new ComponentConfigAdapter();
+ registrator.activate();
+
+ sut.registrator = registrator;
+ sut.resourceService = new MockResourceService();
+
+ replay(coreService, intentExtensionService);
+ }
+
+ @After
+ public void tearDown() {
+ Intent.unbindIdGenerator(idGenerator);
+ }
+
+ /**
+ * We test the proper compilation of mp2Sp1 with the VLAN
+ * encapsulation, trivial selector.
+ */
+ @Test
+ public void testVlanEncapsulationForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForVlan)
+ .links(linksForMp2Sp)
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10),
+ new FilteredConnectPoint(d1p11),
+ new FilteredConnectPoint(d2p10)
+ ))
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10)))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(5));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(intent.selector())
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(intent.selector())
+ .matchInPort(d1p11.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(2));
+ FlowRule ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder(intent.selector())
+ .matchInPort(d2p10.port())
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .setOutput(d3p10.port())
+ .build()
+ ));
+
+ sut.deactivate();
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with the MPLS
+ * encapsulation and trivial selector.
+ */
+ @Test
+ public void testMplsEncapsulationForSp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForMPLS)
+ .links(linksForSp2Mp)
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10)))
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10),
+ new FilteredConnectPoint(d1p11),
+ new FilteredConnectPoint(d2p10)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(3));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p10.port())
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel((LABEL)))
+ .setOutput(d3p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(1));
+ FlowRule ruleS2 = rulesS2.iterator().next();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p1.port())
+ .matchMplsLabel(MplsLabel.mplsLabel((LABEL)))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p0.port())
+ .popMpls(IPV4.ethType())
+ .setOutput(d2p10.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.iterator().next();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel((LABEL)))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .setOutput(d1p10.port())
+ .popMpls(IPV4.ethType())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of mp2sp with the MPLS
+ * encapsulation and filtered selector.
+ */
+ @Test
+ public void testMplsEncapsulationFilteredForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForMPLS)
+ .links(linksForMp2Sp)
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, vlan69Selector)))
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, vlan200Selector),
+ new FilteredConnectPoint(d2p10, vlan300Selector)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(5));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan100Selector)
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan200Selector)
+ .matchInPort(d1p11.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(2));
+ FlowRule ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan300Selector)
+ .matchInPort(d2p10.port())
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(((VlanIdCriterion) vlan69Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d3p10.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with the VLAN
+ * encapsulation and filtered selector.
+ */
+ @Test
+ public void testVlanEncapsulationFilteredForSp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForVlan)
+ .links(linksForSp2Mp)
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, mpls69Selector)))
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, mpls100Selector),
+ new FilteredConnectPoint(d1p11, mpls200Selector),
+ new FilteredConnectPoint(d2p10, mpls80Selector)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(3));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder(mpls69Selector)
+ .matchInPort(d3p10.port())
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d3p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(1));
+ FlowRule ruleS2 = rulesS2.iterator().next();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p1.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p0.port())
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls80Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d2p10.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.iterator().next();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls100Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d1p10.port())
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls200Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of mp2sp with the VLAN
+ * encapsulation, filtered selectors, intent selector and intent treatment.
+ */
+ @Test
+ public void testVlanEncapsulationNonTrivialForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(ipPrefixSelector)
+ .treatment(ethDstTreatment)
+ .constraints(constraintsForVlan)
+ .links(linksForMp2Sp)
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, mpls69Selector)))
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, mpls80Selector),
+ new FilteredConnectPoint(d1p11, mpls100Selector),
+ new FilteredConnectPoint(d2p10, mpls200Selector)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(5));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchInPort(d1p10.port())
+ .matchMplsLabel(((MplsCriterion) mpls80Selector.getCriterion(MPLS_LABEL)).label())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchInPort(d1p11.port())
+ .matchMplsLabel(((MplsCriterion) mpls100Selector.getCriterion(MPLS_LABEL)).label())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(2));
+ FlowRule ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchInPort(d2p10.port())
+ .matchMplsLabel(((MplsCriterion) mpls200Selector.getCriterion(MPLS_LABEL)).label())
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder(ethDstTreatment)
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls69Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d3p10.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with the MPLS
+ * encapsulation, filtered selector, intent selector, and
+ * intent treatment.
+ */
+ @Test
+ public void testMplsEncapsulationNonTrivialForSp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(ipPrefixSelector)
+ .treatment(ethDstTreatment)
+ .constraints(constraintsForMPLS)
+ .links(linksForSp2Mp)
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, vlan69Selector)))
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, vlan200Selector),
+ new FilteredConnectPoint(d2p10, vlan300Selector)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(3));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchInPort(d3p10.port())
+ .matchVlanId(((VlanIdCriterion) vlan69Selector.getCriterion(VLAN_VID)).vlanId())
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d3p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(1));
+ FlowRule ruleS2 = rulesS2.iterator().next();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p1.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p0.port())
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(((VlanIdCriterion) vlan300Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d2p10.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.iterator().next();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(((VlanIdCriterion) vlan100Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p10.port())
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(((VlanIdCriterion) vlan200Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of mp2sp with the MPLS
+ * encapsulation and filtered selectors of different type.
+ */
+ @Test
+ public void testMplsEncapsulationDifferentFilterForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForMPLS)
+ .links(linksForMp2Sp)
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, mpls100Selector)))
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, mpls200Selector),
+ new FilteredConnectPoint(d2p10, vlan200Selector)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(5));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan100Selector)
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(mpls200Selector)
+ .matchInPort(d1p11.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(2));
+ FlowRule ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan200Selector)
+ .matchInPort(d2p10.port())
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ ruleS2 = rulesS2.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d2p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(((MplsCriterion) mpls100Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d3p10.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with the VLAN
+ * encapsulation and filtered selectors of different type.
+ */
+ @Test
+ public void testVlanEncapsulationDifferentFilter() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForVlan)
+ .links(linksForSp2Mp)
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, vlan200Selector)))
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, mpls100Selector),
+ new FilteredConnectPoint(d1p11, vlan100Selector),
+ new FilteredConnectPoint(d2p10, mpls200Selector)
+ ))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(3));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan200Selector)
+ .matchInPort(d3p10.port())
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d3p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(1));
+ FlowRule ruleS2 = rulesS2.iterator().next();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p1.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p0.port())
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls200Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d2p10.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.iterator().next();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls100Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d1p10.port())
+ .setVlanId(((VlanIdCriterion) vlan100Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of p2p with the VLAN
+ * encapsulation and filtered points.
+ */
+ @Test
+ public void testVlanEncapsulationForP2P() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForVlan)
+ .links(linksForMp2Sp)
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p10, vlan100Selector)))
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, mpls200Selector)))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(3));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.iterator().next();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan100Selector)
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(1));
+ FlowRule ruleS2 = rulesS2.iterator().next();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(VlanId.vlanId(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p0.port())
+ .matchVlanId(VlanId.vlanId(LABEL))
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls200Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d3p10.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of p2p with the MPLS
+ * encapsulation and filtered points.
+ */
+ @Test
+ public void testMplsEncapsulationForP2P() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .constraints(constraintsForMPLS)
+ .links(linksForMp2Sp)
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p10, vlan100Selector)))
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p10, mpls200Selector)))
+ .build();
+
+ sut.activate();
+ /*
+ * We use the FIRST_FIT to simplify tests.
+ */
+ LinkCollectionCompiler.labelAllocator.setLabelSelection(LABEL_SELECTION);
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(3));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.iterator().next();
+ assertThat(ruleS1.selector(), is(
+ DefaultTrafficSelector
+ .builder(vlan100Selector)
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .popVlan()
+ .pushMpls()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS2, hasSize(1));
+ FlowRule ruleS2 = rulesS2.iterator().next();
+ assertThat(ruleS2.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d2p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(MplsLabel.mplsLabel(LABEL))
+ .setOutput(d2p1.port())
+ .build()
+ ));
+
+ Collection<FlowRule> rulesS3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS3, hasSize(1));
+ FlowRule ruleS3 = rulesS3.iterator().next();
+ assertThat(ruleS3.selector(), is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d3p0.port())
+ .matchMplsLabel(MplsLabel.mplsLabel(LABEL))
+ .matchEthType(Ethernet.MPLS_UNICAST)
+ .build()
+ ));
+ assertThat(ruleS3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setMpls(((MplsCriterion) mpls200Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d3p10.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
index e3b662a..87103aa 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompilerTest.java
@@ -16,20 +16,16 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.ImmutableSet;
+import org.hamcrest.core.Is;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
-import org.onosproject.TestApplicationId;
import org.onosproject.cfg.ComponentConfigAdapter;
-import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
-import org.onosproject.core.IdGenerator;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultLink;
-import org.onosproject.net.DeviceId;
import org.onosproject.net.FilteredConnectPoint;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
@@ -38,11 +34,13 @@
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.MplsCriterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.LinkCollectionIntent;
-import org.onosproject.net.intent.MockIdGenerator;
import java.util.Collection;
import java.util.Collections;
@@ -58,75 +56,15 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
+import static org.onlab.packet.EthType.EtherType.IPV4;
import static org.onosproject.net.Link.Type.DIRECT;
import static org.onosproject.net.NetTestTools.*;
+import static org.onosproject.net.flow.criteria.Criterion.Type.IN_PORT;
+import static org.onosproject.net.flow.criteria.Criterion.Type.MPLS_LABEL;
+import static org.onosproject.net.flow.criteria.Criterion.Type.VLAN_VID;
+import static org.onosproject.net.flow.instructions.L2ModificationInstruction.*;
-public class LinkCollectionIntentCompilerTest {
-
- private final ApplicationId appId = new TestApplicationId("test");
-
- private final ConnectPoint d1p1 = connectPoint("s1", 1);
- private final ConnectPoint d2p0 = connectPoint("s2", 0);
- private final ConnectPoint d2p1 = connectPoint("s2", 1);
- private final ConnectPoint d3p1 = connectPoint("s3", 1);
- private final ConnectPoint d3p0 = connectPoint("s3", 10);
- private final ConnectPoint d1p0 = connectPoint("s1", 10);
-
- private final DeviceId of1Id = DeviceId.deviceId("of:of1");
- private final DeviceId of2Id = DeviceId.deviceId("of:of2");
- private final DeviceId of3Id = DeviceId.deviceId("of:of3");
- private final DeviceId of4Id = DeviceId.deviceId("of:of4");
-
- private final ConnectPoint of1p1 = connectPoint("of1", 1);
- private final ConnectPoint of1p2 = connectPoint("of1", 2);
- private final ConnectPoint of2p1 = connectPoint("of2", 1);
- private final ConnectPoint of2p2 = connectPoint("of2", 2);
- private final ConnectPoint of2p3 = connectPoint("of2", 3);
- private final ConnectPoint of3p1 = connectPoint("of3", 1);
- private final ConnectPoint of3p2 = connectPoint("of3", 2);
- private final ConnectPoint of4p1 = connectPoint("of4", 1);
- private final ConnectPoint of4p2 = connectPoint("of4", 2);
-
- private final Set<Link> links = ImmutableSet.of(
- DefaultLink.builder().providerId(PID).src(d1p1).dst(d2p0).type(DIRECT).build(),
- DefaultLink.builder().providerId(PID).src(d2p1).dst(d3p1).type(DIRECT).build(),
- DefaultLink.builder().providerId(PID).src(d1p1).dst(d3p1).type(DIRECT).build());
-
- private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
- private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
-
- private final TrafficSelector vlan100Selector = DefaultTrafficSelector.builder()
- .matchVlanId(VlanId.vlanId("100"))
- .build();
-
- private final TrafficSelector vlan200Selector = DefaultTrafficSelector.builder()
- .matchVlanId(VlanId.vlanId("200"))
- .build();
-
- private final TrafficSelector ipPrefixSelector = DefaultTrafficSelector.builder()
- .matchIPDst(IpPrefix.valueOf("192.168.100.0/24"))
- .build();
-
- private final TrafficTreatment ethDstTreatment = DefaultTrafficTreatment.builder()
- .setEthDst(MacAddress.valueOf("C0:FF:EE:C0:FF:EE"))
- .build();
-
- private CoreService coreService;
- private IntentExtensionService intentExtensionService;
- private IntentConfigurableRegistrator registrator;
- private IdGenerator idGenerator = new MockIdGenerator();
-
- private LinkCollectionIntent intent;
-
- private LinkCollectionIntentCompiler sut;
-
-
-
- private List<FlowRule> getFlowRulesByDevice(DeviceId deviceId, Collection<FlowRule> flowRules) {
- return flowRules.stream()
- .filter(fr -> fr.deviceId().equals(deviceId))
- .collect(Collectors.toList());
- }
+public class LinkCollectionIntentCompilerTest extends AbstractLinkCollectionTest {
@Before
public void setUp() {
@@ -181,7 +119,7 @@
// if not found, get() raises an exception
FlowRule rule1 = rules.stream()
- .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .filter(rule -> rule.deviceId().equals(d1p10.deviceId()))
.findFirst()
.get();
assertThat(rule1.selector(), is(
@@ -226,7 +164,7 @@
* `-1 of4 2-
*/
@Test
- public void testFilteredConnectPoint1() {
+ public void testFilteredConnectPointForSp() {
sut.activate();
Set<Link> testLinks = ImmutableSet.of(
DefaultLink.builder().providerId(PID).src(of1p2).dst(of2p1).type(DIRECT).build(),
@@ -346,7 +284,7 @@
* -1 of3 2---/
*/
@Test
- public void testFilteredConnectPoint2() {
+ public void testFilteredConnectPointForMp() {
sut.activate();
Set<Link> testlinks = ImmutableSet.of(
DefaultLink.builder().providerId(PID).src(of1p2).dst(of2p1).type(DIRECT).build(),
@@ -467,7 +405,7 @@
* `-1 of4 2-
*/
@Test
- public void nonTrivialTranslation1() {
+ public void nonTrivialTranslationForSp() {
sut.activate();
Set<Link> testLinks = ImmutableSet.of(
DefaultLink.builder().providerId(PID).src(of1p2).dst(of2p1).type(DIRECT).build(),
@@ -587,7 +525,7 @@
* -1 of3 2---/
*/
@Test
- public void nonTrivialTranslation2() {
+ public void nonTrivialTranslationForMp() {
sut.activate();
Set<Link> testlinks = ImmutableSet.of(
DefaultLink.builder().providerId(PID).src(of1p2).dst(of2p1).type(DIRECT).build(),
@@ -701,4 +639,442 @@
sut.deactivate();
}
+
+ /**
+ * We test the proper compilation of mp2sp with
+ * trivial selector, trivial treatment and 1 hop.
+ */
+ @Test
+ public void singleHopTestForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .links(ImmutableSet.of())
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10),
+ new FilteredConnectPoint(d1p11)
+ ))
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p0)))
+ .build();
+
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(2));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p11.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with
+ * trivial selector, trivial treatment and 1 hop.
+ */
+ @Test
+ public void singleHopTestForSp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .applyTreatmentOnEgress(true)
+ .links(ImmutableSet.of())
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10),
+ new FilteredConnectPoint(d1p11)
+ ))
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p0)))
+ .build();
+
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(1));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder()
+ .matchInPort(d1p0.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setOutput(d1p10.port())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of mp2sp with
+ * trivial selector, trivial treatment, filtered
+ * points and 1 hop.
+ */
+ @Test
+ public void singleHopTestFilteredForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .links(ImmutableSet.of())
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, mpls69Selector)
+ ))
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p0, vlan200Selector)))
+ .build();
+
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(2));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder(vlan100Selector)
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(((VlanIdCriterion) vlan200Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder(mpls69Selector)
+ .matchInPort(d1p11.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(((VlanIdCriterion) vlan200Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with
+ * trivial selector, trivial treatment and 1 hop.
+ */
+ @Test
+ public void singleHopTestFilteredForSp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(selector)
+ .treatment(treatment)
+ .applyTreatmentOnEgress(true)
+ .links(ImmutableSet.of())
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, mpls80Selector)
+ ))
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p0, vlan200Selector)))
+ .build();
+
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(1));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder(vlan200Selector)
+ .matchInPort(d1p0.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setVlanId(((VlanIdCriterion) vlan100Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p10.port())
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls80Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of mp2sp with
+ * selector, treatment, filtered
+ * points and 1 hop.
+ */
+ @Test
+ public void singleHopNonTrivialForMp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(ipPrefixSelector)
+ .treatment(ethDstTreatment)
+ .links(ImmutableSet.of())
+ .filteredIngressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, mpls100Selector)
+ ))
+ .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p0, vlan200Selector)))
+ .build();
+
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(2));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(2));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p10.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchVlanId(((VlanIdCriterion) vlan100Selector.getCriterion(VLAN_VID)).vlanId())
+ .matchInPort(d1p10.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .setVlanId(((VlanIdCriterion) vlan200Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p11.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchMplsLabel(((MplsCriterion) mpls100Selector.getCriterion(MPLS_LABEL)).label())
+ .matchInPort(d1p11.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .popMpls(IPV4.ethType())
+ .pushVlan()
+ .setVlanId(((VlanIdCriterion) vlan200Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p0.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
+ /**
+ * We test the proper compilation of sp2mp with
+ * selector, treatment and 1 hop.
+ */
+ @Test
+ public void singleHopNonTrivialForSp() {
+
+ intent = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .selector(ipPrefixSelector)
+ .treatment(ethDstTreatment)
+ .applyTreatmentOnEgress(true)
+ .links(ImmutableSet.of())
+ .filteredEgressPoints(ImmutableSet.of(
+ new FilteredConnectPoint(d1p10, vlan100Selector),
+ new FilteredConnectPoint(d1p11, mpls200Selector)
+ ))
+ .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p0, vlan200Selector)))
+ .build();
+
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intent, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize(1));
+
+ Collection<FlowRule> rulesS1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d1p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(rulesS1, hasSize(1));
+ FlowRule ruleS1 = rulesS1.stream()
+ .filter(rule -> {
+ PortCriterion inPort = (PortCriterion) rule.selector().getCriterion(IN_PORT);
+ return inPort.port().equals(d1p0.port());
+ })
+ .findFirst()
+ .get();
+ assertThat(ruleS1.selector(), Is.is(
+ DefaultTrafficSelector
+ .builder(ipPrefixSelector)
+ .matchVlanId(((VlanIdCriterion) vlan200Selector.getCriterion(VLAN_VID)).vlanId())
+ .matchInPort(d1p0.port())
+ .build()
+ ));
+ assertThat(ruleS1.treatment(), Is.is(
+ DefaultTrafficTreatment
+ .builder()
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .setVlanId(((VlanIdCriterion) vlan100Selector.getCriterion(VLAN_VID)).vlanId())
+ .setOutput(d1p10.port())
+ .setEthDst(((ModEtherInstruction) ethDstTreatment
+ .allInstructions()
+ .stream()
+ .filter(instruction -> instruction instanceof ModEtherInstruction)
+ .findFirst().get()).mac())
+ .popVlan()
+ .pushMpls()
+ .setMpls(((MplsCriterion) mpls200Selector.getCriterion(MPLS_LABEL)).label())
+ .setOutput(d1p11.port())
+ .build()
+ ));
+
+ sut.deactivate();
+
+ }
+
}