Michele Santuari
Committed by Gerrit Code Review

Support encapsulation in PathIntent

- related to ONOS-3467
- unit test work
- depends on ONOS-3507 and also on the advertisement of VLAN resource
  for different devices.

Change-Id: Ia852c751135b5ca4a16901c6f3a85ceea11514a3
...@@ -15,42 +15,68 @@ ...@@ -15,42 +15,68 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 +import com.google.common.collect.ImmutableList;
19 +import com.google.common.collect.Sets;
18 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference; 23 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality; 24 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 +import org.onlab.packet.VlanId;
23 import org.onosproject.core.ApplicationId; 26 import org.onosproject.core.ApplicationId;
24 import org.onosproject.core.CoreService; 27 import org.onosproject.core.CoreService;
25 import org.onosproject.net.ConnectPoint; 28 import org.onosproject.net.ConnectPoint;
29 +import org.onosproject.net.EncapsulationType;
26 import org.onosproject.net.Link; 30 import org.onosproject.net.Link;
31 +import org.onosproject.net.LinkKey;
27 import org.onosproject.net.flow.DefaultFlowRule; 32 import org.onosproject.net.flow.DefaultFlowRule;
28 import org.onosproject.net.flow.DefaultTrafficSelector; 33 import org.onosproject.net.flow.DefaultTrafficSelector;
29 import org.onosproject.net.flow.DefaultTrafficTreatment; 34 import org.onosproject.net.flow.DefaultTrafficTreatment;
30 import org.onosproject.net.flow.FlowRule; 35 import org.onosproject.net.flow.FlowRule;
31 import org.onosproject.net.flow.TrafficSelector; 36 import org.onosproject.net.flow.TrafficSelector;
32 import org.onosproject.net.flow.TrafficTreatment; 37 import org.onosproject.net.flow.TrafficTreatment;
38 +import org.onosproject.net.flow.criteria.Criterion;
39 +import org.onosproject.net.flow.criteria.VlanIdCriterion;
33 import org.onosproject.net.intent.FlowRuleIntent; 40 import org.onosproject.net.intent.FlowRuleIntent;
34 import org.onosproject.net.intent.Intent; 41 import org.onosproject.net.intent.Intent;
35 import org.onosproject.net.intent.IntentCompiler; 42 import org.onosproject.net.intent.IntentCompiler;
36 import org.onosproject.net.intent.IntentExtensionService; 43 import org.onosproject.net.intent.IntentExtensionService;
37 import org.onosproject.net.intent.PathIntent; 44 import org.onosproject.net.intent.PathIntent;
45 +import org.onosproject.net.intent.constraint.EncapsulationConstraint;
46 +import org.onosproject.net.intent.impl.IntentCompilationException;
47 +import org.onosproject.net.newresource.ResourcePath;
48 +import org.onosproject.net.newresource.ResourceService;
38 import org.onosproject.net.resource.link.LinkResourceAllocations; 49 import org.onosproject.net.resource.link.LinkResourceAllocations;
50 +import org.slf4j.Logger;
39 51
40 -import java.util.ArrayList;
41 import java.util.Collections; 52 import java.util.Collections;
53 +import java.util.HashMap;
54 +import java.util.Iterator;
55 +import java.util.LinkedList;
42 import java.util.List; 56 import java.util.List;
57 +import java.util.Map;
58 +import java.util.Optional;
43 import java.util.Set; 59 import java.util.Set;
60 +import java.util.stream.Collectors;
61 +import java.util.stream.Stream;
62 +
63 +import static org.onosproject.net.LinkKey.linkKey;
64 +import static org.slf4j.LoggerFactory.getLogger;
44 65
45 @Component(immediate = true) 66 @Component(immediate = true)
46 public class PathIntentCompiler implements IntentCompiler<PathIntent> { 67 public class PathIntentCompiler implements IntentCompiler<PathIntent> {
47 68
69 + private final Logger log = getLogger(getClass());
70 +
48 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
49 protected CoreService coreService; 72 protected CoreService coreService;
50 73
51 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
52 protected IntentExtensionService intentManager; 75 protected IntentExtensionService intentManager;
53 76
77 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 + protected ResourceService resourceService;
79 +
54 private ApplicationId appId; 80 private ApplicationId appId;
55 81
56 @Activate 82 @Activate
...@@ -71,7 +97,13 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> { ...@@ -71,7 +97,13 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> {
71 // TODO: implement recompile behavior 97 // TODO: implement recompile behavior
72 98
73 List<Link> links = intent.path().links(); 99 List<Link> links = intent.path().links();
74 - List<FlowRule> rules = new ArrayList<>(links.size() - 1); 100 + List<FlowRule> rules = new LinkedList<>();
101 +
102 + Optional<EncapsulationConstraint> enacpConstraint = intent.constraints().stream()
103 + .filter(constraint -> constraint instanceof EncapsulationConstraint)
104 + .map(x -> (EncapsulationConstraint) x).findAny();
105 + //if no encapsulation or is involved only a single switch use the default behaviour
106 + if (!enacpConstraint.isPresent() || links.size() == 1) {
75 107
76 for (int i = 0; i < links.size() - 1; i++) { 108 for (int i = 0; i < links.size() - 1; i++) {
77 ConnectPoint ingress = links.get(i).dst(); 109 ConnectPoint ingress = links.get(i).dst();
...@@ -82,18 +114,30 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> { ...@@ -82,18 +114,30 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> {
82 rules.add(rule); 114 rules.add(rule);
83 } 115 }
84 116
85 - return Collections.singletonList(new FlowRuleIntent(appId, null, rules, intent.resources())); 117 + return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources()));
118 +
119 + } else {
120 + if (EncapsulationType.VLAN == enacpConstraint.get().encapType()) {
121 + rules = manageVlanEncap(intent);
122 + }
123 + if (EncapsulationType.MPLS == enacpConstraint.get().encapType()) {
124 + //TODO: to be implemented
125 + rules = Collections.emptyList();
126 + }
127 +
128 + return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources()));
129 + }
86 } 130 }
87 131
88 private FlowRule createFlowRule(TrafficSelector originalSelector, TrafficTreatment originalTreatment, 132 private FlowRule createFlowRule(TrafficSelector originalSelector, TrafficTreatment originalTreatment,
89 ConnectPoint ingress, ConnectPoint egress, 133 ConnectPoint ingress, ConnectPoint egress,
90 - int priority, boolean last) { 134 + int priority, boolean applyTreatment) {
91 TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector) 135 TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector)
92 .matchInPort(ingress.port()) 136 .matchInPort(ingress.port())
93 .build(); 137 .build();
94 138
95 TrafficTreatment.Builder treatmentBuilder; 139 TrafficTreatment.Builder treatmentBuilder;
96 - if (last) { 140 + if (applyTreatment) {
97 treatmentBuilder = DefaultTrafficTreatment.builder(originalTreatment); 141 treatmentBuilder = DefaultTrafficTreatment.builder(originalTreatment);
98 } else { 142 } else {
99 treatmentBuilder = DefaultTrafficTreatment.builder(); 143 treatmentBuilder = DefaultTrafficTreatment.builder();
...@@ -110,6 +154,138 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> { ...@@ -110,6 +154,138 @@ public class PathIntentCompiler implements IntentCompiler<PathIntent> {
110 .build(); 154 .build();
111 } 155 }
112 156
157 + private List<FlowRule> manageVlanEncap(PathIntent intent) {
158 + Map<LinkKey, VlanId> vlanIds = assignVlanId(intent);
159 +
160 + Iterator<Link> links = intent.path().links().iterator();
161 + Link srcLink = links.next();
162 +
163 + Link link = links.next();
164 + // List of flow rules to be installed
165 + List<FlowRule> rules = new LinkedList<>();
166 +
167 + // Ingress traffic
168 + VlanId vlanId = vlanIds.get(linkKey(link));
169 + if (vlanId == null) {
170 + throw new IntentCompilationException("No available VLAN ID for " + link);
171 + }
172 + VlanId prevVlanId = vlanId;
173 +
174 + //Tag the traffic with the new VLAN
175 + TrafficTreatment treat = DefaultTrafficTreatment.builder()
176 + .setVlanId(vlanId)
177 + .build();
178 +
179 + rules.add(createFlowRule(intent.selector(), treat, srcLink.dst(), link.src(), intent.priority(), true));
180 +
181 + ConnectPoint prev = link.dst();
182 +
183 + while (links.hasNext()) {
184 +
185 + link = links.next();
186 +
187 + if (links.hasNext()) {
188 + // Transit traffic
189 + VlanId egressVlanId = vlanIds.get(linkKey(link));
190 + if (egressVlanId == null) {
191 + throw new IntentCompilationException("No available VLAN ID for " + link);
192 + }
193 + prevVlanId = egressVlanId;
194 +
195 + TrafficSelector transitSelector = DefaultTrafficSelector.builder()
196 + .matchInPort(prev.port())
197 + .matchVlanId(prevVlanId).build();
198 +
199 + TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder();
200 +
201 + // Set the new vlanId only if the previous one is different
202 + if (!prevVlanId.equals(egressVlanId)) {
203 + transitTreat.setVlanId(egressVlanId);
204 + }
205 + rules.add(createFlowRule(transitSelector,
206 + transitTreat.build(), prev, link.src(), intent.priority(), true));
207 + prev = link.dst();
208 + } else {
209 + // Egress traffic
210 + TrafficSelector egressSelector = DefaultTrafficSelector.builder()
211 + .matchInPort(prev.port())
212 + .matchVlanId(prevVlanId).build();
213 +
214 + //TODO: think to other cases for egress packet restoration
215 + Optional<VlanIdCriterion> vlanCriteria = intent.selector().criteria()
216 + .stream().filter(criteria -> criteria.type() == Criterion.Type.VLAN_VID)
217 + .map(criteria -> (VlanIdCriterion) criteria)
218 + .findAny();
219 + TrafficTreatment.Builder egressTreat = DefaultTrafficTreatment.builder(intent.treatment());
220 + if (vlanCriteria.isPresent()) {
221 + egressTreat.setVlanId(vlanCriteria.get().vlanId());
222 + } else {
223 + egressTreat.popVlan();
224 + }
225 +
226 + rules.add(createFlowRule(egressSelector,
227 + egressTreat.build(), prev, link.src(), intent.priority(), true));
228 + }
229 +
230 + }
231 + return rules;
232 +
233 + }
234 +
235 + private Map<LinkKey, VlanId> assignVlanId(PathIntent intent) {
236 + Set<LinkKey> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
237 + .links().size() - 2);
238 + for (int i = 1; i <= intent.path().links().size() - 2; i++) {
239 + LinkKey link = linkKey(intent.path().links().get(i));
240 + linkRequest.add(link);
241 + // add the inverse link. I want that the VLANID is reserved both for
242 + // the direct and inverse link
243 + linkRequest.add(linkKey(link.dst(), link.src()));
244 + }
245 +
246 + Map<LinkKey, VlanId> vlanIds = findVlanIds(linkRequest);
247 + if (vlanIds.isEmpty()) {
248 + log.warn("No VLAN IDs available");
249 + return Collections.emptyMap();
250 + }
251 +
252 + //same VLANID is used for both directions
253 + Set<ResourcePath> resources = vlanIds.entrySet().stream()
254 + .flatMap(x -> Stream.of(
255 + ResourcePath.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue()),
256 + ResourcePath.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
257 + ))
258 + .collect(Collectors.toSet());
259 + List<org.onosproject.net.newresource.ResourceAllocation> allocations =
260 + resourceService.allocate(intent.id(), ImmutableList.copyOf(resources));
261 + if (allocations.isEmpty()) {
262 + Collections.emptyMap();
263 + }
264 +
265 + return vlanIds;
266 + }
267 +
268 + private Map<LinkKey, VlanId> findVlanIds(Set<LinkKey> links) {
269 + Map<LinkKey, VlanId> vlanIds = new HashMap<>();
270 + for (LinkKey link : links) {
271 + Set<VlanId> forward = findVlanId(link.src());
272 + Set<VlanId> backward = findVlanId(link.dst());
273 + Set<VlanId> common = Sets.intersection(forward, backward);
274 + if (common.isEmpty()) {
275 + continue;
276 + }
277 + vlanIds.put(link, common.iterator().next());
278 + }
279 + return vlanIds;
280 + }
281 +
282 + private Set<VlanId> findVlanId(ConnectPoint cp) {
283 + return resourceService.getAvailableResources(ResourcePath.discrete(cp.deviceId(), cp.port())).stream()
284 + .filter(x -> x.last() instanceof VlanId)
285 + .map(x -> (VlanId) x.last())
286 + .collect(Collectors.toSet());
287 + }
288 +
113 private boolean isLast(List<Link> links, int i) { 289 private boolean isLast(List<Link> links, int i) {
114 return i == links.size() - 2; 290 return i == links.size() - 2;
115 } 291 }
......
...@@ -17,6 +17,7 @@ package org.onosproject.net.intent.impl.compiler; ...@@ -17,6 +17,7 @@ package org.onosproject.net.intent.impl.compiler;
17 17
18 import com.google.common.collect.ImmutableList; 18 import com.google.common.collect.ImmutableList;
19 import org.onlab.packet.MplsLabel; 19 import org.onlab.packet.MplsLabel;
20 +import org.onlab.packet.VlanId;
20 import org.onosproject.net.newresource.ResourceAllocation; 21 import org.onosproject.net.newresource.ResourceAllocation;
21 import org.onosproject.net.newresource.ResourceConsumer; 22 import org.onosproject.net.newresource.ResourceConsumer;
22 import org.onosproject.net.newresource.ResourceListener; 23 import org.onosproject.net.newresource.ResourceListener;
...@@ -25,6 +26,7 @@ import org.onosproject.net.newresource.ResourceService; ...@@ -25,6 +26,7 @@ import org.onosproject.net.newresource.ResourceService;
25 26
26 import java.util.Collection; 27 import java.util.Collection;
27 import java.util.HashMap; 28 import java.util.HashMap;
29 +import java.util.HashSet;
28 import java.util.List; 30 import java.util.List;
29 import java.util.Map; 31 import java.util.Map;
30 import java.util.Optional; 32 import java.util.Optional;
...@@ -91,8 +93,11 @@ class MockResourceService implements ResourceService { ...@@ -91,8 +93,11 @@ class MockResourceService implements ResourceService {
91 93
92 @Override 94 @Override
93 public Collection<ResourcePath> getAvailableResources(ResourcePath parent) { 95 public Collection<ResourcePath> getAvailableResources(ResourcePath parent) {
94 - ResourcePath resource = parent.child(MplsLabel.mplsLabel(10)); 96 +
95 - return ImmutableList.of(resource); 97 + Collection<ResourcePath> resources = new HashSet<ResourcePath>();
98 + resources.add(parent.child(VlanId.vlanId((short) 10)));
99 + resources.add(parent.child(MplsLabel.mplsLabel(10)));
100 + return ImmutableList.copyOf(resources);
96 } 101 }
97 102
98 @Override 103 @Override
......
...@@ -15,14 +15,11 @@ ...@@ -15,14 +15,11 @@
15 */ 15 */
16 package org.onosproject.net.intent.impl.compiler; 16 package org.onosproject.net.intent.impl.compiler;
17 17
18 -import java.util.Arrays; 18 +import com.google.common.collect.ImmutableList;
19 -import java.util.Collection;
20 -import java.util.Collections;
21 -import java.util.List;
22 -
23 import org.junit.After; 19 import org.junit.After;
24 import org.junit.Before; 20 import org.junit.Before;
25 import org.junit.Test; 21 import org.junit.Test;
22 +import org.onlab.packet.VlanId;
26 import org.onosproject.TestApplicationId; 23 import org.onosproject.TestApplicationId;
27 import org.onosproject.core.ApplicationId; 24 import org.onosproject.core.ApplicationId;
28 import org.onosproject.core.CoreService; 25 import org.onosproject.core.CoreService;
...@@ -30,30 +27,38 @@ import org.onosproject.core.IdGenerator; ...@@ -30,30 +27,38 @@ import org.onosproject.core.IdGenerator;
30 import org.onosproject.net.ConnectPoint; 27 import org.onosproject.net.ConnectPoint;
31 import org.onosproject.net.DefaultLink; 28 import org.onosproject.net.DefaultLink;
32 import org.onosproject.net.DefaultPath; 29 import org.onosproject.net.DefaultPath;
30 +import org.onosproject.net.EncapsulationType;
33 import org.onosproject.net.Link; 31 import org.onosproject.net.Link;
34 import org.onosproject.net.flow.DefaultTrafficSelector; 32 import org.onosproject.net.flow.DefaultTrafficSelector;
35 import org.onosproject.net.flow.DefaultTrafficTreatment; 33 import org.onosproject.net.flow.DefaultTrafficTreatment;
36 import org.onosproject.net.flow.FlowRule; 34 import org.onosproject.net.flow.FlowRule;
37 import org.onosproject.net.flow.TrafficSelector; 35 import org.onosproject.net.flow.TrafficSelector;
38 import org.onosproject.net.flow.TrafficTreatment; 36 import org.onosproject.net.flow.TrafficTreatment;
37 +import org.onosproject.net.flow.instructions.Instructions;
38 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
39 import org.onosproject.net.intent.FlowRuleIntent; 39 import org.onosproject.net.intent.FlowRuleIntent;
40 import org.onosproject.net.intent.Intent; 40 import org.onosproject.net.intent.Intent;
41 import org.onosproject.net.intent.IntentExtensionService; 41 import org.onosproject.net.intent.IntentExtensionService;
42 import org.onosproject.net.intent.MockIdGenerator; 42 import org.onosproject.net.intent.MockIdGenerator;
43 import org.onosproject.net.intent.PathIntent; 43 import org.onosproject.net.intent.PathIntent;
44 +import org.onosproject.net.intent.constraint.EncapsulationConstraint;
44 import org.onosproject.net.provider.ProviderId; 45 import org.onosproject.net.provider.ProviderId;
45 46
46 -import static org.easymock.EasyMock.createMock; 47 +import java.util.Arrays;
47 -import static org.easymock.EasyMock.expect; 48 +import java.util.Collection;
48 -import static org.easymock.EasyMock.replay; 49 +import java.util.Collections;
50 +import java.util.List;
51 +import java.util.Set;
52 +import java.util.stream.Collectors;
53 +
54 +import static org.easymock.EasyMock.*;
49 import static org.hamcrest.MatcherAssert.assertThat; 55 import static org.hamcrest.MatcherAssert.assertThat;
50 import static org.hamcrest.Matchers.hasSize; 56 import static org.hamcrest.Matchers.hasSize;
51 import static org.hamcrest.Matchers.is; 57 import static org.hamcrest.Matchers.is;
58 +import static org.hamcrest.number.OrderingComparison.greaterThan;
52 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; 59 import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
53 import static org.onosproject.net.Link.Type.DIRECT; 60 import static org.onosproject.net.Link.Type.DIRECT;
54 -import static org.onosproject.net.NetTestTools.APP_ID; 61 +import static org.onosproject.net.NetTestTools.*;
55 -import static org.onosproject.net.NetTestTools.PID;
56 -import static org.onosproject.net.NetTestTools.connectPoint;
57 62
58 /** 63 /**
59 * Unit tests for PathIntentCompiler. 64 * Unit tests for PathIntentCompiler.
...@@ -85,6 +90,7 @@ public class PathIntentCompilerTest { ...@@ -85,6 +90,7 @@ public class PathIntentCompilerTest {
85 ); 90 );
86 private final int hops = links.size() - 1; 91 private final int hops = links.size() - 1;
87 private PathIntent intent; 92 private PathIntent intent;
93 + private PathIntent constraintIntent;
88 94
89 /** 95 /**
90 * Configures objects used in all the test cases. 96 * Configures objects used in all the test cases.
...@@ -96,6 +102,7 @@ public class PathIntentCompilerTest { ...@@ -96,6 +102,7 @@ public class PathIntentCompilerTest {
96 expect(coreService.registerApplication("org.onosproject.net.intent")) 102 expect(coreService.registerApplication("org.onosproject.net.intent"))
97 .andReturn(appId); 103 .andReturn(appId);
98 sut.coreService = coreService; 104 sut.coreService = coreService;
105 + sut.resourceService = new MockResourceService();
99 106
100 Intent.bindIdGenerator(idGenerator); 107 Intent.bindIdGenerator(idGenerator);
101 108
...@@ -106,6 +113,14 @@ public class PathIntentCompilerTest { ...@@ -106,6 +113,14 @@ public class PathIntentCompilerTest {
106 .priority(PRIORITY) 113 .priority(PRIORITY)
107 .path(new DefaultPath(pid, links, hops)) 114 .path(new DefaultPath(pid, links, hops))
108 .build(); 115 .build();
116 + constraintIntent = PathIntent.builder()
117 + .appId(APP_ID)
118 + .selector(selector)
119 + .treatment(treatment)
120 + .priority(PRIORITY)
121 + .constraints(ImmutableList.of(new EncapsulationConstraint(EncapsulationType.VLAN)))
122 + .path(new DefaultPath(pid, links, hops))
123 + .build();
109 intentExtensionService = createMock(IntentExtensionService.class); 124 intentExtensionService = createMock(IntentExtensionService.class);
110 intentExtensionService.registerCompiler(PathIntent.class, sut); 125 intentExtensionService.registerCompiler(PathIntent.class, sut);
111 intentExtensionService.unregisterCompiler(PathIntent.class); 126 intentExtensionService.unregisterCompiler(PathIntent.class);
...@@ -169,4 +184,91 @@ public class PathIntentCompilerTest { ...@@ -169,4 +184,91 @@ public class PathIntentCompilerTest {
169 184
170 sut.deactivate(); 185 sut.deactivate();
171 } 186 }
187 +
188 + /**
189 + * Tests the compilation behavior of the path intent compiler in case of
190 + * encasulation costraint {@link EncapsulationConstraint}.
191 + */
192 + @Test
193 + public void testEncapCompile() {
194 + sut.activate();
195 +
196 + List<Intent> compiled = sut.compile(constraintIntent, Collections.emptyList(), Collections.emptySet());
197 + assertThat(compiled, hasSize(1));
198 +
199 + Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules();
200 + assertThat(rules, hasSize(3));
201 +
202 + FlowRule rule1 = rules.stream()
203 + .filter(x -> x.deviceId().equals(d1p0.deviceId()))
204 + .findFirst()
205 + .get();
206 + assertThat(rule1.deviceId(), is(d1p0.deviceId()));
207 + assertThat(rule1.priority(), is(intent.priority()));
208 + verifyEncapSelector(rule1.selector(), d1p0, VlanId.NONE);
209 + VlanId vlanToEncap = verifyEncapTreatment(rule1.treatment(), d1p1, true, false);
210 +
211 + FlowRule rule2 = rules.stream()
212 + .filter(x -> x.deviceId().equals(d2p0.deviceId()))
213 + .findFirst()
214 + .get();
215 + assertThat(rule2.deviceId(), is(d2p0.deviceId()));
216 + assertThat(rule2.priority(), is(intent.priority()));
217 + verifyEncapSelector(rule2.selector(), d2p0, vlanToEncap);
218 + verifyEncapTreatment(rule2.treatment(), d2p1, false, false);
219 +
220 + FlowRule rule3 = rules.stream()
221 + .filter(x -> x.deviceId().equals(d3p0.deviceId()))
222 + .findFirst()
223 + .get();
224 + assertThat(rule3.deviceId(), is(d3p1.deviceId()));
225 + assertThat(rule3.priority(), is(intent.priority()));
226 + verifyEncapSelector(rule3.selector(), d3p1, vlanToEncap);
227 + verifyEncapTreatment(rule3.treatment(), d3p0, false, true);
228 +
229 + sut.deactivate();
230 + }
231 +
232 +
233 + private VlanId verifyEncapTreatment(TrafficTreatment trafficTreatment,
234 + ConnectPoint egress, boolean isIngress, boolean isEgress) {
235 + Set<Instructions.OutputInstruction> ruleOutput = trafficTreatment.allInstructions().stream()
236 + .filter(treat -> treat instanceof Instructions.OutputInstruction)
237 + .map(treat -> (Instructions.OutputInstruction) treat)
238 + .collect(Collectors.toSet());
239 + assertThat(ruleOutput, hasSize(1));
240 + assertThat((ruleOutput.iterator().next()).port(), is(egress.port()));
241 + VlanId vlanToEncap = VlanId.NONE;
242 + if (isIngress && !isEgress) {
243 + Set<L2ModificationInstruction.ModVlanIdInstruction> vlanRules = trafficTreatment.allInstructions().stream()
244 + .filter(treat -> treat instanceof L2ModificationInstruction.ModVlanIdInstruction)
245 + .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x)
246 + .collect(Collectors.toSet());
247 + assertThat(vlanRules, hasSize(1));
248 + L2ModificationInstruction.ModVlanIdInstruction vlanRule = vlanRules.iterator().next();
249 + assertThat(vlanRule.vlanId().toShort(), greaterThan((short) 0));
250 + vlanToEncap = vlanRule.vlanId();
251 + } else if (!isIngress && !isEgress) {
252 + assertThat(trafficTreatment.allInstructions().stream()
253 + .filter(treat -> treat instanceof L2ModificationInstruction.ModVlanIdInstruction)
254 + .collect(Collectors.toSet()), hasSize(0));
255 + } else {
256 + assertThat(trafficTreatment.allInstructions().stream()
257 + .filter(treat -> treat instanceof L2ModificationInstruction.ModVlanIdInstruction)
258 + .collect(Collectors.toSet()), hasSize(0));
259 + assertThat(trafficTreatment.allInstructions().stream()
260 + .filter(treat -> treat instanceof L2ModificationInstruction.PopVlanInstruction)
261 + .collect(Collectors.toSet()), hasSize(1));
262 +
263 + }
264 +
265 + return vlanToEncap;
266 +
267 + }
268 +
269 + private void verifyEncapSelector(TrafficSelector trafficSelector, ConnectPoint ingress, VlanId vlanToMatch) {
270 +
271 + is(DefaultTrafficSelector.builder(selector).matchInPort(ingress.port())
272 + .matchVlanId(vlanToMatch).build());
273 + }
172 } 274 }
......