Michele Santuari
Committed by Gerrit Code Review

Add MPLS encapsulation behaviour ONOS-3467

- MPLS encapsulation using constraint
- New MPLS encapsulation test
- Fix VLAN encapsulation test

Change-Id: I94670bcd51a95a0272f786681e51d6785a56c4f5
...@@ -31,7 +31,11 @@ import java.util.Optional; ...@@ -31,7 +31,11 @@ import java.util.Optional;
31 31
32 /** 32 /**
33 * Installs MPLS intents. 33 * Installs MPLS intents.
34 + *
35 + * @deprecated in Goldeneye Release, in favour of encapsulation
36 + * constraint {@link org.onosproject.net.intent.constraint.EncapsulationConstraint}
34 */ 37 */
38 +@Deprecated
35 @Command(scope = "onos", name = "add-mpls-intent", description = "Installs mpls connectivity intent") 39 @Command(scope = "onos", name = "add-mpls-intent", description = "Installs mpls connectivity intent")
36 public class AddMplsIntent extends ConnectivityIntentCommand { 40 public class AddMplsIntent extends ConnectivityIntentCommand {
37 41
......
...@@ -34,8 +34,14 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -34,8 +34,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
34 34
35 /** 35 /**
36 * Abstraction of MPLS label-switched connectivity. 36 * Abstraction of MPLS label-switched connectivity.
37 + *
38 + * @deprecated in Goldeneye Release, in favour of encapsulation
39 + * constraint {@link org.onosproject.net.intent.constraint.EncapsulationConstraint}
40 + * with Encasulation type {@link org.onosproject.net.EncapsulationType} MPLS.
41 + *
37 */ 42 */
38 @Beta 43 @Beta
44 +@Deprecated
39 public final class MplsIntent extends ConnectivityIntent { 45 public final class MplsIntent extends ConnectivityIntent {
40 46
41 private final ConnectPoint ingressPoint; 47 private final ConnectPoint ingressPoint;
......
...@@ -30,8 +30,12 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -30,8 +30,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
30 30
31 /** 31 /**
32 * Abstraction of explicit MPLS label-switched path. 32 * Abstraction of explicit MPLS label-switched path.
33 + *
34 + * @deprecated in Goldeneye Release, in favour of encapsulation
35 + * constraint {@link org.onosproject.net.intent.constraint.EncapsulationConstraint}
33 */ 36 */
34 @Beta 37 @Beta
38 +@Deprecated
35 public final class MplsPathIntent extends PathIntent { 39 public final class MplsPathIntent extends PathIntent {
36 40
37 private final Optional<MplsLabel> ingressLabel; 41 private final Optional<MplsLabel> ingressLabel;
......
...@@ -36,7 +36,11 @@ import org.onosproject.net.intent.MplsPathIntent; ...@@ -36,7 +36,11 @@ import org.onosproject.net.intent.MplsPathIntent;
36 import org.onosproject.net.provider.ProviderId; 36 import org.onosproject.net.provider.ProviderId;
37 import org.onosproject.net.resource.link.LinkResourceAllocations; 37 import org.onosproject.net.resource.link.LinkResourceAllocations;
38 38
39 - 39 +/**
40 + * @deprecated in Goldeneye Release, in favour of encapsulation
41 + * constraint {@link org.onosproject.net.intent.constraint.EncapsulationConstraint}
42 + */
43 +@Deprecated
40 @Component(immediate = true) 44 @Component(immediate = true)
41 public class MplsIntentCompiler extends ConnectivityIntentCompiler<MplsIntent> { 45 public class MplsIntentCompiler extends ConnectivityIntentCompiler<MplsIntent> {
42 46
......
...@@ -68,6 +68,11 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -68,6 +68,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
68 import static org.onosproject.net.LinkKey.linkKey; 68 import static org.onosproject.net.LinkKey.linkKey;
69 import static org.slf4j.LoggerFactory.getLogger; 69 import static org.slf4j.LoggerFactory.getLogger;
70 70
71 +/**
72 + * @deprecated in Goldeneye Release, in favour of encapsulation
73 + * constraint {@link org.onosproject.net.intent.constraint.EncapsulationConstraint}
74 + */
75 +@Deprecated
71 @Component(immediate = true) 76 @Component(immediate = true)
72 public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> { 77 public class MplsPathIntentCompiler implements IntentCompiler<MplsPathIntent> {
73 78
......
...@@ -25,6 +25,9 @@ import java.util.Set; ...@@ -25,6 +25,9 @@ import java.util.Set;
25 import java.util.stream.Collectors; 25 import java.util.stream.Collectors;
26 import java.util.stream.Stream; 26 import java.util.stream.Stream;
27 27
28 +import org.onlab.packet.EthType;
29 +import org.onlab.packet.Ethernet;
30 +import org.onlab.packet.MplsLabel;
28 import org.onlab.packet.VlanId; 31 import org.onlab.packet.VlanId;
29 import org.onosproject.net.ConnectPoint; 32 import org.onosproject.net.ConnectPoint;
30 import org.onosproject.net.DeviceId; 33 import org.onosproject.net.DeviceId;
...@@ -35,12 +38,16 @@ import org.onosproject.net.flow.DefaultTrafficTreatment; ...@@ -35,12 +38,16 @@ import org.onosproject.net.flow.DefaultTrafficTreatment;
35 import org.onosproject.net.flow.TrafficSelector; 38 import org.onosproject.net.flow.TrafficSelector;
36 import org.onosproject.net.flow.TrafficTreatment; 39 import org.onosproject.net.flow.TrafficTreatment;
37 import org.onosproject.net.flow.criteria.Criterion; 40 import org.onosproject.net.flow.criteria.Criterion;
41 +import org.onosproject.net.flow.criteria.EthTypeCriterion;
42 +import org.onosproject.net.flow.criteria.MplsCriterion;
38 import org.onosproject.net.flow.criteria.VlanIdCriterion; 43 import org.onosproject.net.flow.criteria.VlanIdCriterion;
44 +import org.onosproject.net.flow.instructions.Instruction;
39 import org.onosproject.net.flow.instructions.L2ModificationInstruction; 45 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
40 import org.onosproject.net.intent.PathIntent; 46 import org.onosproject.net.intent.PathIntent;
41 import org.onosproject.net.intent.constraint.EncapsulationConstraint; 47 import org.onosproject.net.intent.constraint.EncapsulationConstraint;
42 import org.onosproject.net.intent.impl.IntentCompilationException; 48 import org.onosproject.net.intent.impl.IntentCompilationException;
43 import org.onosproject.net.newresource.Resource; 49 import org.onosproject.net.newresource.Resource;
50 +import org.onosproject.net.newresource.ResourceAllocation;
44 import org.onosproject.net.newresource.ResourceService; 51 import org.onosproject.net.newresource.ResourceService;
45 import org.onosproject.net.newresource.Resources; 52 import org.onosproject.net.newresource.Resources;
46 import org.slf4j.Logger; 53 import org.slf4j.Logger;
...@@ -227,6 +234,185 @@ public class PathCompiler<T> { ...@@ -227,6 +234,185 @@ public class PathCompiler<T> {
227 } 234 }
228 } 235 }
229 236
237 + private Map<LinkKey, MplsLabel> assignMplsLabel(PathCompilerCreateFlow creator, PathIntent intent) {
238 + Set<LinkKey> linkRequest =
239 + Sets.newHashSetWithExpectedSize(intent.path()
240 + .links().size() - 2);
241 + for (int i = 1; i <= intent.path().links().size() - 2; i++) {
242 + LinkKey link = linkKey(intent.path().links().get(i));
243 + linkRequest.add(link);
244 + // add the inverse link. I want that the VLANID is reserved both for
245 + // the direct and inverse link
246 + linkRequest.add(linkKey(link.dst(), link.src()));
247 + }
248 +
249 + Map<LinkKey, MplsLabel> labels = findMplsLabels(creator, linkRequest);
250 + if (labels.isEmpty()) {
251 + throw new IntentCompilationException("No available MPLS Label");
252 + }
253 +
254 + // for short term solution: same label is used for both directions
255 + // TODO: introduce the concept of Tx and Rx resources of a port
256 + Set<Resource> resources = labels.entrySet().stream()
257 + .flatMap(x -> Stream.of(
258 + Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
259 + .resource(),
260 + Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
261 + .resource()
262 + ))
263 + .collect(Collectors.toSet());
264 + List<ResourceAllocation> allocations =
265 + creator.resourceService().allocate(intent.id(), ImmutableList.copyOf(resources));
266 + if (allocations.isEmpty()) {
267 + Collections.emptyMap();
268 + }
269 +
270 + return labels;
271 + }
272 +
273 + private Map<LinkKey, MplsLabel> findMplsLabels(PathCompilerCreateFlow creator, Set<LinkKey> links) {
274 + Map<LinkKey, MplsLabel> labels = new HashMap<>();
275 + for (LinkKey link : links) {
276 + Set<MplsLabel> forward = findMplsLabel(creator, link.src());
277 + Set<MplsLabel> backward = findMplsLabel(creator, link.dst());
278 + Set<MplsLabel> common = Sets.intersection(forward, backward);
279 + if (common.isEmpty()) {
280 + continue;
281 + }
282 + labels.put(link, common.iterator().next());
283 + }
284 +
285 + return labels;
286 + }
287 +
288 + private Set<MplsLabel> findMplsLabel(PathCompilerCreateFlow creator, ConnectPoint cp) {
289 + return creator.resourceService().getAvailableResourceValues(
290 + Resources.discrete(cp.deviceId(), cp.port()).id(),
291 + MplsLabel.class);
292 + }
293 +
294 + private void manageMplsEncap(PathCompilerCreateFlow<T> creator, List<T> flows,
295 + List<DeviceId> devices,
296 + PathIntent intent) {
297 + Map<LinkKey, MplsLabel> mplsLabels = assignMplsLabel(creator, intent);
298 +
299 + Iterator<Link> links = intent.path().links().iterator();
300 + Link srcLink = links.next();
301 +
302 + Link link = links.next();
303 + // List of flow rules to be installed
304 +
305 + // Ingress traffic
306 + MplsLabel mplsLabel = mplsLabels.get(linkKey(link));
307 + if (mplsLabel == null) {
308 + throw new IntentCompilationException("No available MPLS Label for " + link);
309 + }
310 + MplsLabel prevMplsLabel = mplsLabel;
311 +
312 + Optional<MplsCriterion> mplsCriterion = intent.selector().criteria()
313 + .stream().filter(criterion -> criterion.type() == Criterion.Type.MPLS_LABEL)
314 + .map(criterion -> (MplsCriterion) criterion)
315 + .findAny();
316 +
317 + //Push MPLS if selector does not include MPLS
318 + TrafficTreatment.Builder treatBuilder = DefaultTrafficTreatment.builder();
319 + if (!mplsCriterion.isPresent()) {
320 + treatBuilder.pushMpls();
321 + }
322 + //Tag the traffic with the new encapsulation MPLS label
323 + treatBuilder.setMpls(mplsLabel);
324 + creator.createFlow(intent.selector(), treatBuilder.build(),
325 + srcLink.dst(), link.src(), intent.priority(), true, flows, devices);
326 +
327 + ConnectPoint prev = link.dst();
328 +
329 + while (links.hasNext()) {
330 +
331 + link = links.next();
332 +
333 + if (links.hasNext()) {
334 + // Transit traffic
335 + MplsLabel transitMplsLabel = mplsLabels.get(linkKey(link));
336 + if (transitMplsLabel == null) {
337 + throw new IntentCompilationException("No available MPLS label for " + link);
338 + }
339 + prevMplsLabel = transitMplsLabel;
340 +
341 + TrafficSelector transitSelector = DefaultTrafficSelector.builder()
342 + .matchInPort(prev.port())
343 + .matchEthType(Ethernet.MPLS_UNICAST)
344 + .matchMplsLabel(prevMplsLabel).build();
345 +
346 + TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder();
347 +
348 + // Set the new MPLS Label only if the previous one is different
349 + if (!prevMplsLabel.equals(transitMplsLabel)) {
350 + transitTreat.setMpls(transitMplsLabel);
351 + }
352 + creator.createFlow(transitSelector,
353 + transitTreat.build(), prev, link.src(), intent.priority(), true, flows, devices);
354 + prev = link.dst();
355 + } else {
356 + TrafficSelector.Builder egressSelector = DefaultTrafficSelector.builder()
357 + .matchInPort(prev.port())
358 + .matchEthType(Ethernet.MPLS_UNICAST)
359 + .matchMplsLabel(prevMplsLabel);
360 + TrafficTreatment.Builder egressTreat = DefaultTrafficTreatment.builder(intent.treatment());
361 +
362 + // Egress traffic
363 + // check if the treatement is popVlan or setVlan (rewrite),
364 + // than selector needs to match any VlanId
365 + for (Instruction instruct : intent.treatment().allInstructions()) {
366 + if (instruct instanceof L2ModificationInstruction) {
367 + L2ModificationInstruction l2Mod = (L2ModificationInstruction) instruct;
368 + if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
369 + break;
370 + }
371 + if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP ||
372 + l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
373 + egressSelector.matchVlanId(VlanId.ANY);
374 + }
375 + }
376 + }
377 +
378 + if (mplsCriterion.isPresent()) {
379 + egressTreat.setMpls(mplsCriterion.get().label());
380 + } else {
381 + egressTreat.popMpls(outputEthType(intent.selector()));
382 + }
383 +
384 +
385 + if (mplsCriterion.isPresent()) {
386 + egressTreat.setMpls(mplsCriterion.get().label());
387 + } else {
388 + egressTreat.popVlan();
389 + }
390 +
391 + creator.createFlow(egressSelector.build(),
392 + egressTreat.build(), prev, link.src(), intent.priority(), true, flows, devices);
393 + }
394 +
395 + }
396 +
397 + }
398 +
399 + private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) {
400 + return labels.get(link);
401 + }
402 +
403 + // if the ingress ethertype is defined, the egress traffic
404 + // will be use that value, otherwise the IPv4 ethertype is used.
405 + private EthType outputEthType(TrafficSelector selector) {
406 + Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
407 + if (c != null && c instanceof EthTypeCriterion) {
408 + EthTypeCriterion ethertype = (EthTypeCriterion) c;
409 + return ethertype.ethType();
410 + } else {
411 + return EthType.EtherType.IPV4.ethType();
412 + }
413 + }
414 +
415 +
230 /** 416 /**
231 * Compiles an intent down to flows. 417 * Compiles an intent down to flows.
232 * 418 *
...@@ -263,7 +449,10 @@ public class PathCompiler<T> { ...@@ -263,7 +449,10 @@ public class PathCompiler<T> {
263 switch (type) { 449 switch (type) {
264 case VLAN: 450 case VLAN:
265 manageVlanEncap(creator, flows, devices, intent); 451 manageVlanEncap(creator, flows, devices, intent);
266 - // TODO: implement MPLS case here 452 + break;
453 + case MPLS:
454 + manageMplsEncap(creator, flows, devices, intent);
455 + break;
267 default: 456 default:
268 // Nothing to do 457 // Nothing to do
269 } 458 }
......
...@@ -15,10 +15,7 @@ ...@@ -15,10 +15,7 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 -import java.util.LinkedList; 18 +import com.google.common.collect.ImmutableList;
19 -import java.util.List;
20 -import java.util.Set;
21 -
22 import org.apache.felix.scr.annotations.Activate; 19 import org.apache.felix.scr.annotations.Activate;
23 import org.apache.felix.scr.annotations.Component; 20 import org.apache.felix.scr.annotations.Component;
24 import org.apache.felix.scr.annotations.Deactivate; 21 import org.apache.felix.scr.annotations.Deactivate;
...@@ -42,10 +39,13 @@ import org.onosproject.net.newresource.ResourceService; ...@@ -42,10 +39,13 @@ import org.onosproject.net.newresource.ResourceService;
42 import org.onosproject.net.resource.link.LinkResourceAllocations; 39 import org.onosproject.net.resource.link.LinkResourceAllocations;
43 import org.slf4j.Logger; 40 import org.slf4j.Logger;
44 41
45 -import com.google.common.collect.ImmutableList; 42 +import java.util.LinkedList;
43 +import java.util.List;
44 +import java.util.Set;
46 45
47 import static org.slf4j.LoggerFactory.getLogger; 46 import static org.slf4j.LoggerFactory.getLogger;
48 47
48 +
49 @Component(immediate = true) 49 @Component(immediate = true)
50 public class PathIntentCompiler 50 public class PathIntentCompiler
51 extends PathCompiler<FlowRule> 51 extends PathCompiler<FlowRule>
...@@ -84,6 +84,7 @@ public class PathIntentCompiler ...@@ -84,6 +84,7 @@ public class PathIntentCompiler
84 List<DeviceId> devices = new LinkedList<>(); 84 List<DeviceId> devices = new LinkedList<>();
85 compile(this, intent, rules, devices); 85 compile(this, intent, rules, devices);
86 86
87 +
87 return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources())); 88 return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources()));
88 } 89 }
89 90
...@@ -97,12 +98,14 @@ public class PathIntentCompiler ...@@ -97,12 +98,14 @@ public class PathIntentCompiler
97 return resourceService; 98 return resourceService;
98 } 99 }
99 100
101 +
100 @Override 102 @Override
101 public void createFlow(TrafficSelector originalSelector, TrafficTreatment originalTreatment, 103 public void createFlow(TrafficSelector originalSelector, TrafficTreatment originalTreatment,
102 ConnectPoint ingress, ConnectPoint egress, 104 ConnectPoint ingress, ConnectPoint egress,
103 int priority, boolean applyTreatment, 105 int priority, boolean applyTreatment,
104 List<FlowRule> rules, 106 List<FlowRule> rules,
105 List<DeviceId> devices) { 107 List<DeviceId> devices) {
108 +
106 TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector) 109 TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector)
107 .matchInPort(ingress.port()) 110 .matchInPort(ingress.port())
108 .build(); 111 .build();
...@@ -123,5 +126,6 @@ public class PathIntentCompiler ...@@ -123,5 +126,6 @@ public class PathIntentCompiler
123 .fromApp(appId) 126 .fromApp(appId)
124 .makePermanent() 127 .makePermanent()
125 .build()); 128 .build());
129 +
126 } 130 }
127 } 131 }
......
...@@ -19,6 +19,8 @@ import com.google.common.collect.ImmutableList; ...@@ -19,6 +19,8 @@ import com.google.common.collect.ImmutableList;
19 import org.junit.After; 19 import org.junit.After;
20 import org.junit.Before; 20 import org.junit.Before;
21 import org.junit.Test; 21 import org.junit.Test;
22 +import org.onlab.packet.Ethernet;
23 +import org.onlab.packet.MplsLabel;
22 import org.onlab.packet.VlanId; 24 import org.onlab.packet.VlanId;
23 import org.onosproject.TestApplicationId; 25 import org.onosproject.TestApplicationId;
24 import org.onosproject.cfg.ComponentConfigAdapter; 26 import org.onosproject.cfg.ComponentConfigAdapter;
...@@ -28,6 +30,7 @@ import org.onosproject.core.IdGenerator; ...@@ -28,6 +30,7 @@ import org.onosproject.core.IdGenerator;
28 import org.onosproject.net.ConnectPoint; 30 import org.onosproject.net.ConnectPoint;
29 import org.onosproject.net.DefaultLink; 31 import org.onosproject.net.DefaultLink;
30 import org.onosproject.net.DefaultPath; 32 import org.onosproject.net.DefaultPath;
33 +import org.onosproject.net.DeviceId;
31 import org.onosproject.net.EncapsulationType; 34 import org.onosproject.net.EncapsulationType;
32 import org.onosproject.net.Link; 35 import org.onosproject.net.Link;
33 import org.onosproject.net.flow.DefaultTrafficSelector; 36 import org.onosproject.net.flow.DefaultTrafficSelector;
...@@ -52,14 +55,18 @@ import java.util.List; ...@@ -52,14 +55,18 @@ import java.util.List;
52 import java.util.Set; 55 import java.util.Set;
53 import java.util.stream.Collectors; 56 import java.util.stream.Collectors;
54 57
55 -import static org.easymock.EasyMock.*; 58 +import static org.easymock.EasyMock.createMock;
59 +import static org.easymock.EasyMock.expect;
60 +import static org.easymock.EasyMock.replay;
56 import static org.hamcrest.MatcherAssert.assertThat; 61 import static org.hamcrest.MatcherAssert.assertThat;
57 import static org.hamcrest.Matchers.hasSize; 62 import static org.hamcrest.Matchers.hasSize;
58 import static org.hamcrest.Matchers.is; 63 import static org.hamcrest.Matchers.is;
59 import static org.hamcrest.number.OrderingComparison.greaterThan; 64 import static org.hamcrest.number.OrderingComparison.greaterThan;
60 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; 65 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
61 import static org.onosproject.net.Link.Type.DIRECT; 66 import static org.onosproject.net.Link.Type.DIRECT;
62 -import static org.onosproject.net.NetTestTools.*; 67 +import static org.onosproject.net.NetTestTools.APP_ID;
68 +import static org.onosproject.net.NetTestTools.PID;
69 +import static org.onosproject.net.NetTestTools.connectPoint;
63 70
64 /** 71 /**
65 * Unit tests for PathIntentCompiler. 72 * Unit tests for PathIntentCompiler.
...@@ -99,8 +106,9 @@ public class PathIntentCompilerTest { ...@@ -99,8 +106,9 @@ public class PathIntentCompilerTest {
99 ); 106 );
100 private final int hops = links.size() - 1; 107 private final int hops = links.size() - 1;
101 private PathIntent intent; 108 private PathIntent intent;
102 - private PathIntent constraintIntent; 109 + private PathIntent constraintVlanIntent;
103 private PathIntent constrainIngressEgressVlanIntent; 110 private PathIntent constrainIngressEgressVlanIntent;
111 + private PathIntent constraintMplsIntent;
104 112
105 /** 113 /**
106 * Configures objects used in all the test cases. 114 * Configures objects used in all the test cases.
...@@ -123,8 +131,9 @@ public class PathIntentCompilerTest { ...@@ -123,8 +131,9 @@ public class PathIntentCompilerTest {
123 .priority(PRIORITY) 131 .priority(PRIORITY)
124 .path(new DefaultPath(pid, links, hops)) 132 .path(new DefaultPath(pid, links, hops))
125 .build(); 133 .build();
134 +
126 //Intent with VLAN encap without egress VLAN 135 //Intent with VLAN encap without egress VLAN
127 - constraintIntent = PathIntent.builder() 136 + constraintVlanIntent = PathIntent.builder()
128 .appId(APP_ID) 137 .appId(APP_ID)
129 .selector(selector) 138 .selector(selector)
130 .treatment(treatment) 139 .treatment(treatment)
...@@ -132,6 +141,7 @@ public class PathIntentCompilerTest { ...@@ -132,6 +141,7 @@ public class PathIntentCompilerTest {
132 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN))) 141 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
133 .path(new DefaultPath(pid, links, hops)) 142 .path(new DefaultPath(pid, links, hops))
134 .build(); 143 .build();
144 +
135 //Intent with VLAN encap with ingress and egress VLAN 145 //Intent with VLAN encap with ingress and egress VLAN
136 constrainIngressEgressVlanIntent = PathIntent.builder() 146 constrainIngressEgressVlanIntent = PathIntent.builder()
137 .appId(APP_ID) 147 .appId(APP_ID)
...@@ -141,6 +151,15 @@ public class PathIntentCompilerTest { ...@@ -141,6 +151,15 @@ public class PathIntentCompilerTest {
141 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN))) 151 .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
142 .path(new DefaultPath(pid, links, hops)) 152 .path(new DefaultPath(pid, links, hops))
143 .build(); 153 .build();
154 +
155 + constraintMplsIntent = PathIntent.builder()
156 + .appId(APP_ID)
157 + .selector(selector)
158 + .treatment(treatment)
159 + .priority(PRIORITY)
160 + .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.MPLS)))
161 + .path(new DefaultPath(pid, links, hops))
162 + .build();
144 intentExtensionService = createMock(IntentExtensionService.class); 163 intentExtensionService = createMock(IntentExtensionService.class);
145 intentExtensionService.registerCompiler(PathIntent.class, sut); 164 intentExtensionService.registerCompiler(PathIntent.class, sut);
146 intentExtensionService.unregisterCompiler(PathIntent.class); 165 intentExtensionService.unregisterCompiler(PathIntent.class);
...@@ -179,34 +198,32 @@ public class PathIntentCompilerTest { ...@@ -179,34 +198,32 @@ public class PathIntentCompilerTest {
179 .filter(x -> x.deviceId().equals(d1p0.deviceId())) 198 .filter(x -> x.deviceId().equals(d1p0.deviceId()))
180 .findFirst() 199 .findFirst()
181 .get(); 200 .get();
182 - assertThat(rule1.deviceId(), is(d1p0.deviceId())); 201 + verifyIdAndPriority(rule1, d1p0.deviceId());
183 assertThat(rule1.selector(), 202 assertThat(rule1.selector(),
184 is(DefaultTrafficSelector.builder(selector).matchInPort(d1p0.port()).build())); 203 is(DefaultTrafficSelector.builder(selector).matchInPort(d1p0.port()).build()));
185 assertThat(rule1.treatment(), 204 assertThat(rule1.treatment(),
186 is(DefaultTrafficTreatment.builder().setOutput(d1p1.port()).build())); 205 is(DefaultTrafficTreatment.builder().setOutput(d1p1.port()).build()));
187 - assertThat(rule1.priority(), is(intent.priority())); 206 +
188 207
189 FlowRule rule2 = rules.stream() 208 FlowRule rule2 = rules.stream()
190 .filter(x -> x.deviceId().equals(d2p0.deviceId())) 209 .filter(x -> x.deviceId().equals(d2p0.deviceId()))
191 .findFirst() 210 .findFirst()
192 .get(); 211 .get();
193 - assertThat(rule2.deviceId(), is(d2p0.deviceId())); 212 + verifyIdAndPriority(rule2, d2p0.deviceId());
194 assertThat(rule2.selector(), 213 assertThat(rule2.selector(),
195 is(DefaultTrafficSelector.builder(selector).matchInPort(d2p0.port()).build())); 214 is(DefaultTrafficSelector.builder(selector).matchInPort(d2p0.port()).build()));
196 assertThat(rule2.treatment(), 215 assertThat(rule2.treatment(),
197 is(DefaultTrafficTreatment.builder().setOutput(d2p1.port()).build())); 216 is(DefaultTrafficTreatment.builder().setOutput(d2p1.port()).build()));
198 - assertThat(rule2.priority(), is(intent.priority()));
199 217
200 FlowRule rule3 = rules.stream() 218 FlowRule rule3 = rules.stream()
201 .filter(x -> x.deviceId().equals(d3p0.deviceId())) 219 .filter(x -> x.deviceId().equals(d3p0.deviceId()))
202 .findFirst() 220 .findFirst()
203 .get(); 221 .get();
204 - assertThat(rule3.deviceId(), is(d3p1.deviceId())); 222 + verifyIdAndPriority(rule3, d3p1.deviceId());
205 assertThat(rule3.selector(), 223 assertThat(rule3.selector(),
206 is(DefaultTrafficSelector.builder(selector).matchInPort(d3p1.port()).build())); 224 is(DefaultTrafficSelector.builder(selector).matchInPort(d3p1.port()).build()));
207 assertThat(rule3.treatment(), 225 assertThat(rule3.treatment(),
208 is(DefaultTrafficTreatment.builder(treatment).setOutput(d3p0.port()).build())); 226 is(DefaultTrafficTreatment.builder(treatment).setOutput(d3p0.port()).build()));
209 - assertThat(rule3.priority(), is(intent.priority()));
210 227
211 sut.deactivate(); 228 sut.deactivate();
212 } 229 }
...@@ -216,10 +233,10 @@ public class PathIntentCompilerTest { ...@@ -216,10 +233,10 @@ public class PathIntentCompilerTest {
216 * VLAN {@link EncapsulationType} encapsulation constraint {@link EncapsulationConstraint}. 233 * VLAN {@link EncapsulationType} encapsulation constraint {@link EncapsulationConstraint}.
217 */ 234 */
218 @Test 235 @Test
219 - public void testEncapCompile() { 236 + public void testVlanEncapCompile() {
220 sut.activate(); 237 sut.activate();
221 238
222 - List<Intent> compiled = sut.compile(constraintIntent, Collections.emptyList(), Collections.emptySet()); 239 + List<Intent> compiled = sut.compile(constraintVlanIntent, Collections.emptyList(), Collections.emptySet());
223 assertThat(compiled, hasSize(1)); 240 assertThat(compiled, hasSize(1));
224 241
225 Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); 242 Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
...@@ -229,28 +246,26 @@ public class PathIntentCompilerTest { ...@@ -229,28 +246,26 @@ public class PathIntentCompilerTest {
229 .filter(x -> x.deviceId().equals(d1p0.deviceId())) 246 .filter(x -> x.deviceId().equals(d1p0.deviceId()))
230 .findFirst() 247 .findFirst()
231 .get(); 248 .get();
232 - assertThat(rule1.deviceId(), is(d1p0.deviceId())); 249 + verifyIdAndPriority(rule1, d1p0.deviceId());
233 - assertThat(rule1.priority(), is(intent.priority())); 250 + assertThat(rule1.selector(), is(DefaultTrafficSelector.builder(selector)
234 - verifyEncapSelector(rule1.selector(), d1p0, VlanId.NONE); 251 + .matchInPort(d1p0.port()).build()));
235 - VlanId vlanToEncap = verifyEncapTreatment(rule1.treatment(), d1p1, true, false); 252 + VlanId vlanToEncap = verifyVlanEncapTreatment(rule1.treatment(), d1p1, true, false);
236 253
237 FlowRule rule2 = rules.stream() 254 FlowRule rule2 = rules.stream()
238 .filter(x -> x.deviceId().equals(d2p0.deviceId())) 255 .filter(x -> x.deviceId().equals(d2p0.deviceId()))
239 .findFirst() 256 .findFirst()
240 .get(); 257 .get();
241 - assertThat(rule2.deviceId(), is(d2p0.deviceId())); 258 + verifyIdAndPriority(rule2, d2p0.deviceId());
242 - assertThat(rule2.priority(), is(intent.priority())); 259 + verifyVlanEncapSelector(rule2.selector(), d2p0, vlanToEncap);
243 - verifyEncapSelector(rule2.selector(), d2p0, vlanToEncap); 260 + verifyVlanEncapTreatment(rule2.treatment(), d2p1, false, false);
244 - verifyEncapTreatment(rule2.treatment(), d2p1, false, false);
245 261
246 FlowRule rule3 = rules.stream() 262 FlowRule rule3 = rules.stream()
247 .filter(x -> x.deviceId().equals(d3p0.deviceId())) 263 .filter(x -> x.deviceId().equals(d3p0.deviceId()))
248 .findFirst() 264 .findFirst()
249 .get(); 265 .get();
250 - assertThat(rule3.deviceId(), is(d3p1.deviceId())); 266 + verifyIdAndPriority(rule3, d3p1.deviceId());
251 - assertThat(rule3.priority(), is(intent.priority())); 267 + verifyVlanEncapSelector(rule3.selector(), d3p1, vlanToEncap);
252 - verifyEncapSelector(rule3.selector(), d3p1, vlanToEncap); 268 + verifyVlanEncapTreatment(rule3.treatment(), d3p0, false, true);
253 - verifyEncapTreatment(rule3.treatment(), d3p0, false, true);
254 269
255 sut.deactivate(); 270 sut.deactivate();
256 } 271 }
...@@ -275,27 +290,24 @@ public class PathIntentCompilerTest { ...@@ -275,27 +290,24 @@ public class PathIntentCompilerTest {
275 .filter(x -> x.deviceId().equals(d1p0.deviceId())) 290 .filter(x -> x.deviceId().equals(d1p0.deviceId()))
276 .findFirst() 291 .findFirst()
277 .get(); 292 .get();
278 - assertThat(rule1.deviceId(), is(d1p0.deviceId())); 293 + verifyIdAndPriority(rule1, d1p0.deviceId());
279 - assertThat(rule1.priority(), is(intent.priority())); 294 + verifyVlanEncapSelector(rule1.selector(), d1p0, ingressVlan);
280 - verifyEncapSelector(rule1.selector(), d1p0, ingressVlan); 295 + VlanId vlanToEncap = verifyVlanEncapTreatment(rule1.treatment(), d1p1, true, false);
281 - VlanId vlanToEncap = verifyEncapTreatment(rule1.treatment(), d1p1, true, false);
282 296
283 FlowRule rule2 = rules.stream() 297 FlowRule rule2 = rules.stream()
284 .filter(x -> x.deviceId().equals(d2p0.deviceId())) 298 .filter(x -> x.deviceId().equals(d2p0.deviceId()))
285 .findFirst() 299 .findFirst()
286 .get(); 300 .get();
287 - assertThat(rule2.deviceId(), is(d2p0.deviceId())); 301 + verifyIdAndPriority(rule2, d2p0.deviceId());
288 - assertThat(rule2.priority(), is(intent.priority())); 302 + verifyVlanEncapSelector(rule2.selector(), d2p0, vlanToEncap);
289 - verifyEncapSelector(rule2.selector(), d2p0, vlanToEncap); 303 + verifyVlanEncapTreatment(rule2.treatment(), d2p1, false, false);
290 - verifyEncapTreatment(rule2.treatment(), d2p1, false, false);
291 304
292 FlowRule rule3 = rules.stream() 305 FlowRule rule3 = rules.stream()
293 .filter(x -> x.deviceId().equals(d3p0.deviceId())) 306 .filter(x -> x.deviceId().equals(d3p0.deviceId()))
294 .findFirst() 307 .findFirst()
295 .get(); 308 .get();
296 - assertThat(rule3.deviceId(), is(d3p1.deviceId())); 309 + verifyIdAndPriority(rule3, d3p1.deviceId());
297 - assertThat(rule3.priority(), is(intent.priority())); 310 + verifyVlanEncapSelector(rule3.selector(), d3p1, vlanToEncap);
298 - verifyEncapSelector(rule3.selector(), d3p1, vlanToEncap);
299 Set<L2ModificationInstruction.ModVlanIdInstruction> vlanMod = rule3.treatment().allInstructions().stream() 311 Set<L2ModificationInstruction.ModVlanIdInstruction> vlanMod = rule3.treatment().allInstructions().stream()
300 .filter(treat -> treat instanceof L2ModificationInstruction.ModVlanIdInstruction) 312 .filter(treat -> treat instanceof L2ModificationInstruction.ModVlanIdInstruction)
301 .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x) 313 .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x)
...@@ -311,7 +323,7 @@ public class PathIntentCompilerTest { ...@@ -311,7 +323,7 @@ public class PathIntentCompilerTest {
311 sut.deactivate(); 323 sut.deactivate();
312 } 324 }
313 325
314 - private VlanId verifyEncapTreatment(TrafficTreatment trafficTreatment, 326 + private VlanId verifyVlanEncapTreatment(TrafficTreatment trafficTreatment,
315 ConnectPoint egress, boolean isIngress, boolean isEgress) { 327 ConnectPoint egress, boolean isIngress, boolean isEgress) {
316 Set<Instructions.OutputInstruction> ruleOutput = trafficTreatment.allInstructions().stream() 328 Set<Instructions.OutputInstruction> ruleOutput = trafficTreatment.allInstructions().stream()
317 .filter(treat -> treat instanceof Instructions.OutputInstruction) 329 .filter(treat -> treat instanceof Instructions.OutputInstruction)
...@@ -347,9 +359,101 @@ public class PathIntentCompilerTest { ...@@ -347,9 +359,101 @@ public class PathIntentCompilerTest {
347 359
348 } 360 }
349 361
350 - private void verifyEncapSelector(TrafficSelector trafficSelector, ConnectPoint ingress, VlanId vlanToMatch) { 362 + private void verifyVlanEncapSelector(TrafficSelector trafficSelector, ConnectPoint ingress, VlanId vlanToMatch) {
363 +
364 + assertThat(trafficSelector, is(DefaultTrafficSelector.builder().matchInPort(ingress.port())
365 + .matchVlanId(vlanToMatch).build()));
366 + }
367 +
368 + /**
369 + * Tests the compilation behavior of the path intent compiler in case of
370 + * encasulation costraint {@link EncapsulationConstraint}.
371 + */
372 + @Test
373 + public void testMplsEncapCompile() {
374 + sut.activate();
375 +
376 + List<Intent> compiled = sut.compile(constraintMplsIntent, Collections.emptyList(), Collections.emptySet());
377 + assertThat(compiled, hasSize(1));
378 +
379 + Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
380 + assertThat(rules, hasSize(3));
381 +
382 + FlowRule rule1 = rules.stream()
383 + .filter(x -> x.deviceId().equals(d1p0.deviceId()))
384 + .findFirst()
385 + .get();
386 + verifyIdAndPriority(rule1, d1p0.deviceId());
387 + assertThat(rule1.selector(), is(DefaultTrafficSelector.builder(selector)
388 + .matchInPort(d1p0.port()).build()));
389 + MplsLabel mplsLabelToEncap = verifyMplsEncapTreatment(rule1.treatment(), d1p1, true, false);
390 +
391 + FlowRule rule2 = rules.stream()
392 + .filter(x -> x.deviceId().equals(d2p0.deviceId()))
393 + .findFirst()
394 + .get();
395 + verifyIdAndPriority(rule2, d2p0.deviceId());
396 + verifyMplsEncapSelector(rule2.selector(), d2p0, mplsLabelToEncap);
397 + verifyMplsEncapTreatment(rule2.treatment(), d2p1, false, false);
398 +
399 + FlowRule rule3 = rules.stream()
400 + .filter(x -> x.deviceId().equals(d3p0.deviceId()))
401 + .findFirst()
402 + .get();
403 + verifyIdAndPriority(rule3, d3p1.deviceId());
404 + verifyMplsEncapSelector(rule3.selector(), d3p1, mplsLabelToEncap);
405 + verifyMplsEncapTreatment(rule3.treatment(), d3p0, false, true);
406 +
407 + sut.deactivate();
408 + }
409 +
410 +
411 + private MplsLabel verifyMplsEncapTreatment(TrafficTreatment trafficTreatment,
412 + ConnectPoint egress, boolean isIngress, boolean isEgress) {
413 + Set<Instructions.OutputInstruction> ruleOutput = trafficTreatment.allInstructions().stream()
414 + .filter(treat -> treat instanceof Instructions.OutputInstruction)
415 + .map(treat -> (Instructions.OutputInstruction) treat)
416 + .collect(Collectors.toSet());
417 + assertThat(ruleOutput, hasSize(1));
418 + assertThat((ruleOutput.iterator().next()).port(), is(egress.port()));
419 + MplsLabel mplsToEncap = MplsLabel.mplsLabel(0);
420 + if (isIngress && !isEgress) {
421 + Set<L2ModificationInstruction.ModMplsLabelInstruction> mplsRules =
422 + trafficTreatment.allInstructions().stream()
423 + .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
424 + .map(x -> (L2ModificationInstruction.ModMplsLabelInstruction) x)
425 + .collect(Collectors.toSet());
426 + assertThat(mplsRules, hasSize(1));
427 + L2ModificationInstruction.ModMplsLabelInstruction mplsRule = mplsRules.iterator().next();
428 + assertThat(mplsRule.mplsLabel().toInt(), greaterThan(0));
429 + mplsToEncap = mplsRule.mplsLabel();
430 + } else if (!isIngress && !isEgress) {
431 + assertThat(trafficTreatment.allInstructions().stream()
432 + .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
433 + .collect(Collectors.toSet()), hasSize(0));
434 + } else {
435 + assertThat(trafficTreatment.allInstructions().stream()
436 + .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
437 + .collect(Collectors.toSet()), hasSize(0));
438 + assertThat(trafficTreatment.allInstructions().stream()
439 + .filter(treat -> treat instanceof L2ModificationInstruction.PushHeaderInstructions)
440 + .collect(Collectors.toSet()), hasSize(1));
441 +
442 + }
443 +
444 + return mplsToEncap;
445 +
446 + }
447 +
448 + private void verifyMplsEncapSelector(TrafficSelector trafficSelector, ConnectPoint ingress, MplsLabel mplsLabel) {
449 +
450 + assertThat(trafficSelector, is(DefaultTrafficSelector.builder()
451 + .matchInPort(ingress.port()).matchEthType(Ethernet.MPLS_UNICAST)
452 + .matchMplsLabel(mplsLabel).build()));
453 + }
351 454
352 - is(DefaultTrafficSelector.builder(selector).matchInPort(ingress.port()) 455 + private void verifyIdAndPriority(FlowRule rule, DeviceId deviceId) {
353 - .matchVlanId(vlanToMatch).build()); 456 + assertThat(rule.deviceId(), is(deviceId));
457 + assertThat(rule.priority(), is(PRIORITY));
354 } 458 }
355 } 459 }
......