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
Showing
8 changed files
with
223 additions
and
7 deletions
... | @@ -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 | } | ... | ... |
This diff is collapsed. Click to expand it.
-
Please register or login to post a comment