[ONOS-4387] Support for multiple selectors in mp2sp intents
Changes:
- Adds extension to mp2sp intents;
- Adds extension to linkcollection intents;
- Adds extension to mp2sp compiler;
- Adds extension to linkcollection compiler;
- Adds unit tests for both mp2sp and linkcollection intents;
Change-Id: I673c2b660d2364c510b1b3050ed3626ad2f37bda
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 9fbedb9..b37095a 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
@@ -48,6 +48,7 @@
import org.onosproject.net.intent.LinkCollectionIntent;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@@ -155,12 +156,15 @@
*
* @param intent the intent to compile
* @param inPort the input port
+ * @param deviceId the current device
* @param outPorts the output ports
* @param ingressPorts the ingress ports
* @param egressPorts the egress ports
* @return the forwarding instruction object which encapsulates treatment and selector
*/
- protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent, PortNumber inPort,
+ protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent,
+ PortNumber inPort,
+ DeviceId deviceId,
Set<PortNumber> outPorts,
Set<PortNumber> ingressPorts,
Set<PortNumber> egressPorts) {
@@ -178,8 +182,27 @@
intentTreatment = ingressTreatmentBuilder.build();
if (ingressPorts.contains(inPort)) {
- selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
- treatment = intentTreatment;
+ if (intent.ingressSelectors() != null && !intent.ingressSelectors().isEmpty()) {
+ /**
+ * We iterate on the ingress points looking for the connect point
+ * associated to inPort.
+ */
+ Optional<ConnectPoint> connectPoint = intent.ingressPoints()
+ .stream()
+ .filter(ingressPoint -> ingressPoint.port().equals(inPort)
+ && ingressPoint.deviceId().equals(deviceId))
+ .findFirst();
+ if (connectPoint.isPresent()) {
+ selectorBuilder = DefaultTrafficSelector
+ .builder(intent.ingressSelectors().get(connectPoint.get()));
+ } else {
+ throw new IntentCompilationException("Looking for connect point associated to the selector." +
+ "inPort not in IngressPoints");
+ }
+ } else {
+ selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
+ }
+ treatment = this.updateBuilder(ingressTreatmentBuilder, selectorBuilder.build()).build();
} else {
selectorBuilder = this.createSelectorFromFwdInstructions(
new ForwardingInstructions(intentTreatment, intent.selector())
@@ -207,6 +230,18 @@
}
/**
+ * Update the original builder with the necessary operations
+ * to have a correct forwarding given an ingress selector.
+ *
+ * @param treatmentBuilder the builder to modify
+ * @return the new treatment created
+ */
+ private TrafficTreatment.Builder updateBuilder(TrafficTreatment.Builder treatmentBuilder,
+ TrafficSelector intentSelector) {
+ return treatmentBuilder;
+ }
+
+ /**
* Update the selector builder using a L0 instruction.
*
* @param builder the builder to update
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 7c2157c..83547e2 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
@@ -98,6 +98,7 @@
inPorts.forEach(inport -> {
ForwardingInstructions instructions = this.createForwardingInstructions(intent,
inport,
+ deviceId,
outPorts,
copyIngressPorts,
copyEgressPorts);
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 7ffff6b..0d6ad0a 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
@@ -115,6 +115,7 @@
inPorts.forEach(inport -> {
ForwardingInstructions instructions = this.createForwardingInstructions(intent,
inport,
+ deviceId,
outPorts,
copyIngressPorts,
copyEgressPorts);
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
index 4aee117..00ed9b2 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
@@ -124,6 +124,7 @@
.links(Sets.newHashSet(links.values()))
.ingressPoints(intent.ingressPoints())
.egressPoints(ImmutableSet.of(intent.egressPoint()))
+ .ingressSelectors(intent.ingressSelectors())
.priority(intent.priority())
.constraints(intent.constraints())
.build();
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 acac7df..8e89d14 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,9 +16,11 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.packet.VlanId;
import org.onosproject.TestApplicationId;
import org.onosproject.cfg.ComponentConfigAdapter;
import org.onosproject.core.ApplicationId;
@@ -32,6 +34,8 @@
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentExtensionService;
@@ -41,7 +45,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
@@ -62,6 +68,7 @@
private final ConnectPoint d2p0 = connectPoint("s2", 0);
private final ConnectPoint d2p1 = connectPoint("s2", 1);
private final ConnectPoint d3p1 = connectPoint("s3", 1);
+ private final ConnectPoint d3p2 = connectPoint("s3", 9);
private final ConnectPoint d3p0 = connectPoint("s3", 10);
private final ConnectPoint d1p0 = connectPoint("s1", 10);
@@ -70,15 +77,38 @@
DefaultLink.builder().providerId(PID).src(d2p1).dst(d3p1).type(DIRECT).build(),
DefaultLink.builder().providerId(PID).src(d1p1).dst(d3p1).type(DIRECT).build());
+ private final Set<Link> linksMultiple = ImmutableSet.of(
+ DefaultLink.builder().providerId(PID).src(d3p1).dst(d2p0).type(DIRECT).build());
+
private final TrafficSelector selector = DefaultTrafficSelector.builder().build();
private final TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
+ private final VlanId ingressVlan1 = VlanId.vlanId("10");
+ private final TrafficSelector selectorVlan1 = DefaultTrafficSelector
+ .builder()
+ .matchVlanId(ingressVlan1)
+ .build();
+
+ private final VlanId ingressVlan2 = VlanId.vlanId("20");
+ private final TrafficSelector selectorVlan2 = DefaultTrafficSelector
+ .builder()
+ .matchVlanId(ingressVlan2)
+ .build();
+
+ private final VlanId egressVlan = VlanId.vlanId("666");
+ private final TrafficTreatment vlanTreatment = DefaultTrafficTreatment
+ .builder()
+ .setVlanId(egressVlan)
+ .build();
+
private CoreService coreService;
private IntentExtensionService intentExtensionService;
private IntentConfigurableRegistrator registrator;
private IdGenerator idGenerator = new MockIdGenerator();
private LinkCollectionIntent intent;
+ private LinkCollectionIntent intentMultiple;
+
private LinkCollectionIntentCompiler sut;
@@ -100,6 +130,15 @@
.ingressPoints(ImmutableSet.of(d1p1))
.egressPoints(ImmutableSet.of(d3p1))
.build();
+ intentMultiple = LinkCollectionIntent.builder()
+ .appId(APP_ID)
+ .treatment(vlanTreatment)
+ .links(linksMultiple)
+ .ingressPoints(ImmutableSet.of(d3p0, d3p2))
+ .egressPoints(ImmutableSet.of(d2p1))
+ .ingressSelectors(this.createIngressSelectors())
+ .build();
+
intentExtensionService = createMock(IntentExtensionService.class);
intentExtensionService.registerCompiler(LinkCollectionIntent.class, sut);
intentExtensionService.unregisterCompiler(LinkCollectionIntent.class);
@@ -168,4 +207,99 @@
sut.deactivate();
}
+
+ @Test
+ public void testCompileMultipleSelectors() {
+ sut.activate();
+
+ List<Intent> compiled = sut.compile(intentMultiple, Collections.emptyList());
+ assertThat(compiled, hasSize(1));
+
+
+ Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
+ assertThat(rules, hasSize((linksMultiple.size()) + intentMultiple.ingressPoints().size()));
+
+ Set<FlowRule> d3Rules = rules
+ .parallelStream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(d3Rules, hasSize(intentMultiple.ingressPoints().size()));
+
+ FlowRule rule1 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId())
+ &&
+ rule.selector().getCriterion(Criterion.Type.IN_PORT).equals(Criteria.matchInPort(d3p0.port())))
+ .findFirst()
+ .get();
+ assertThat(rule1.selector(), is(
+ DefaultTrafficSelector
+ .builder(intentMultiple.selector())
+ .matchInPort(d3p0.port())
+ .matchVlanId(ingressVlan1)
+ .build()
+ ));
+ assertThat(rule1.treatment(), is(
+ DefaultTrafficTreatment
+ .builder(intentMultiple.treatment())
+ .setOutput(d3p1.port())
+ .build()
+ ));
+ assertThat(rule1.priority(), is(intentMultiple.priority()));
+
+ FlowRule rule2 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d3p0.deviceId())
+ &&
+ rule.selector().getCriterion(Criterion.Type.IN_PORT).equals(Criteria.matchInPort(d3p2.port())))
+ .findFirst()
+ .get();
+ assertThat(rule2.selector(), is(
+ DefaultTrafficSelector
+ .builder(intentMultiple.selector())
+ .matchInPort(d3p2.port())
+ .matchVlanId(ingressVlan2)
+ .build()
+ ));
+ assertThat(rule2.treatment(), is(
+ DefaultTrafficTreatment
+ .builder(intentMultiple.treatment())
+ .setOutput(d3p1.port())
+ .build()
+ ));
+ assertThat(rule1.priority(), is(intentMultiple.priority()));
+
+ Set<FlowRule> d2Rules = rules
+ .parallelStream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .collect(Collectors.toSet());
+ assertThat(d2Rules, hasSize(intentMultiple.egressPoints().size()));
+
+ // We do not need in_port filter
+ FlowRule rule3 = rules.stream()
+ .filter(rule -> rule.deviceId().equals(d2p0.deviceId()))
+ .findFirst()
+ .get();
+ assertThat(rule3.selector(), is(
+ DefaultTrafficSelector
+ .builder(intentMultiple.selector())
+ .matchInPort(d2p0.port())
+ .matchVlanId(egressVlan)
+ .build()
+ ));
+ assertThat(rule3.treatment(), is(
+ DefaultTrafficTreatment
+ .builder()
+ .setOutput(d2p1.port())
+ .build()
+ ));
+ assertThat(rule3.priority(), is(intentMultiple.priority()));
+
+ sut.deactivate();
+ }
+
+ public Map<ConnectPoint, TrafficSelector> createIngressSelectors() {
+ Map<ConnectPoint, TrafficSelector> mapToReturn = Maps.newHashMap();
+ mapToReturn.put(d3p0, selectorVlan1);
+ mapToReturn.put(d3p2, selectorVlan2);
+ return mapToReturn;
+ }
}