Committed by
Gerrit Code Review
ONOS-2513 Fix entire MP2SP intent failing on partial connectivity loss
* Added PartialFailureContraint to MP2SP intent to allow partial connectivity. This means the intent remains installed as long as at least one ingress point can reach the egress point. * Intents with this constraint are recompiled on ObjectiveTracker triggers even if not in FAILED state * MP2SP intent compiler can compute a partial tree if constraint is set * ObjectiveTracker recompiles intents on any link event * SDN-IP MP2SP intents now use PartialFailureConstraint Ported from onos-1.2 branch. Change-Id: I32eaa198fae1dfba021d9251c8f855573f0e1d7d
Showing
9 changed files
with
161 additions
and
50 deletions
... | @@ -15,19 +15,8 @@ | ... | @@ -15,19 +15,8 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.sdnip; | 16 | package org.onosproject.sdnip; |
17 | 17 | ||
18 | -import java.util.Collection; | 18 | +import com.google.common.collect.ImmutableList; |
19 | -import java.util.HashMap; | 19 | +import com.google.common.util.concurrent.ThreadFactoryBuilder; |
20 | -import java.util.HashSet; | ||
21 | -import java.util.LinkedList; | ||
22 | -import java.util.List; | ||
23 | -import java.util.Map; | ||
24 | -import java.util.Objects; | ||
25 | -import java.util.Set; | ||
26 | -import java.util.concurrent.ConcurrentHashMap; | ||
27 | -import java.util.concurrent.ExecutorService; | ||
28 | -import java.util.concurrent.Executors; | ||
29 | -import java.util.concurrent.Semaphore; | ||
30 | - | ||
31 | import org.onlab.packet.Ethernet; | 20 | import org.onlab.packet.Ethernet; |
32 | import org.onlab.packet.IpAddress; | 21 | import org.onlab.packet.IpAddress; |
33 | import org.onlab.packet.IpPrefix; | 22 | import org.onlab.packet.IpPrefix; |
... | @@ -40,15 +29,17 @@ import org.onosproject.net.flow.DefaultTrafficSelector; | ... | @@ -40,15 +29,17 @@ import org.onosproject.net.flow.DefaultTrafficSelector; |
40 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 29 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
41 | import org.onosproject.net.flow.TrafficSelector; | 30 | import org.onosproject.net.flow.TrafficSelector; |
42 | import org.onosproject.net.flow.TrafficTreatment; | 31 | import org.onosproject.net.flow.TrafficTreatment; |
43 | -import org.onosproject.net.flow.criteria.IPCriterion; | ||
44 | import org.onosproject.net.flow.criteria.Criterion; | 32 | import org.onosproject.net.flow.criteria.Criterion; |
33 | +import org.onosproject.net.flow.criteria.IPCriterion; | ||
45 | import org.onosproject.net.host.HostService; | 34 | import org.onosproject.net.host.HostService; |
35 | +import org.onosproject.net.intent.Constraint; | ||
46 | import org.onosproject.net.intent.Intent; | 36 | import org.onosproject.net.intent.Intent; |
47 | import org.onosproject.net.intent.IntentService; | 37 | import org.onosproject.net.intent.IntentService; |
48 | import org.onosproject.net.intent.IntentState; | 38 | import org.onosproject.net.intent.IntentState; |
49 | import org.onosproject.net.intent.Key; | 39 | import org.onosproject.net.intent.Key; |
50 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; | 40 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
51 | import org.onosproject.net.intent.PointToPointIntent; | 41 | import org.onosproject.net.intent.PointToPointIntent; |
42 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
52 | import org.onosproject.routing.FibListener; | 43 | import org.onosproject.routing.FibListener; |
53 | import org.onosproject.routing.FibUpdate; | 44 | import org.onosproject.routing.FibUpdate; |
54 | import org.onosproject.routing.IntentRequestListener; | 45 | import org.onosproject.routing.IntentRequestListener; |
... | @@ -58,7 +49,18 @@ import org.onosproject.routing.config.RoutingConfigurationService; | ... | @@ -58,7 +49,18 @@ import org.onosproject.routing.config.RoutingConfigurationService; |
58 | import org.slf4j.Logger; | 49 | import org.slf4j.Logger; |
59 | import org.slf4j.LoggerFactory; | 50 | import org.slf4j.LoggerFactory; |
60 | 51 | ||
61 | -import com.google.common.util.concurrent.ThreadFactoryBuilder; | 52 | +import java.util.Collection; |
53 | +import java.util.HashMap; | ||
54 | +import java.util.HashSet; | ||
55 | +import java.util.LinkedList; | ||
56 | +import java.util.List; | ||
57 | +import java.util.Map; | ||
58 | +import java.util.Objects; | ||
59 | +import java.util.Set; | ||
60 | +import java.util.concurrent.ConcurrentHashMap; | ||
61 | +import java.util.concurrent.ExecutorService; | ||
62 | +import java.util.concurrent.Executors; | ||
63 | +import java.util.concurrent.Semaphore; | ||
62 | 64 | ||
63 | import static com.google.common.base.Preconditions.checkArgument; | 65 | import static com.google.common.base.Preconditions.checkArgument; |
64 | import static com.google.common.base.Preconditions.checkNotNull; | 66 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -70,6 +72,8 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -70,6 +72,8 @@ import static com.google.common.base.Preconditions.checkNotNull; |
70 | public class IntentSynchronizer implements FibListener, IntentRequestListener { | 72 | public class IntentSynchronizer implements FibListener, IntentRequestListener { |
71 | private static final int PRIORITY_OFFSET = 100; | 73 | private static final int PRIORITY_OFFSET = 100; |
72 | private static final int PRIORITY_MULTIPLIER = 5; | 74 | private static final int PRIORITY_MULTIPLIER = 5; |
75 | + protected static final ImmutableList<Constraint> CONSTRAINTS | ||
76 | + = ImmutableList.of(new PartialFailureConstraint()); | ||
73 | 77 | ||
74 | private static final Logger log = | 78 | private static final Logger log = |
75 | LoggerFactory.getLogger(IntentSynchronizer.class); | 79 | LoggerFactory.getLogger(IntentSynchronizer.class); |
... | @@ -375,6 +379,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -375,6 +379,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
375 | .ingressPoints(ingressPorts) | 379 | .ingressPoints(ingressPorts) |
376 | .egressPoint(egressPort) | 380 | .egressPoint(egressPort) |
377 | .priority(priority) | 381 | .priority(priority) |
382 | + .constraints(CONSTRAINTS) | ||
378 | .build(); | 383 | .build(); |
379 | } | 384 | } |
380 | 385 | ||
... | @@ -425,6 +430,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -425,6 +430,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
425 | .ingressPoints(ingressPoints) | 430 | .ingressPoints(ingressPoints) |
426 | .egressPoint(egressPoint) | 431 | .egressPoint(egressPoint) |
427 | .priority(priority) | 432 | .priority(priority) |
433 | + .constraints(CONSTRAINTS) | ||
428 | .build(); | 434 | .build(); |
429 | 435 | ||
430 | log.trace("Generates ConnectivityInternetToHost intent {}", intent); | 436 | log.trace("Generates ConnectivityInternetToHost intent {}", intent); |
... | @@ -923,6 +929,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -923,6 +929,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
923 | .ingressPoints(ingressPoints) | 929 | .ingressPoints(ingressPoints) |
924 | .egressPoint(dstConnectPoint) | 930 | .egressPoint(dstConnectPoint) |
925 | .priority(priority) | 931 | .priority(priority) |
932 | + .constraints(CONSTRAINTS) | ||
926 | .build(); | 933 | .build(); |
927 | 934 | ||
928 | log.trace("Generates ConnectivityHostToHost = {} ", intent); | 935 | log.trace("Generates ConnectivityHostToHost = {} ", intent); |
... | @@ -950,6 +957,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -950,6 +957,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
950 | .ingressPoints(ingressPoints) | 957 | .ingressPoints(ingressPoints) |
951 | .egressPoint(existingIntent.egressPoint()) | 958 | .egressPoint(existingIntent.egressPoint()) |
952 | .priority(existingIntent.priority()) | 959 | .priority(existingIntent.priority()) |
960 | + .constraints(CONSTRAINTS) | ||
953 | .build(); | 961 | .build(); |
954 | 962 | ||
955 | log.trace("Update an existing MultiPointToSinglePointIntent " | 963 | log.trace("Update an existing MultiPointToSinglePointIntent " | ... | ... |
... | @@ -239,6 +239,7 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -239,6 +239,7 @@ public class IntentSyncTest extends AbstractIntentTest { |
239 | .treatment(treatmentBuilder.build()) | 239 | .treatment(treatmentBuilder.build()) |
240 | .ingressPoints(ingressPoints) | 240 | .ingressPoints(ingressPoints) |
241 | .egressPoint(SW1_ETH1) | 241 | .egressPoint(SW1_ETH1) |
242 | + .constraints(IntentSynchronizer.CONSTRAINTS) | ||
242 | .build(); | 243 | .build(); |
243 | 244 | ||
244 | // Setup the expected intents | 245 | // Setup the expected intents |
... | @@ -301,6 +302,7 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -301,6 +302,7 @@ public class IntentSyncTest extends AbstractIntentTest { |
301 | .treatment(treatmentBuilder.build()) | 302 | .treatment(treatmentBuilder.build()) |
302 | .ingressPoints(ingressPoints) | 303 | .ingressPoints(ingressPoints) |
303 | .egressPoint(SW4_ETH1) | 304 | .egressPoint(SW4_ETH1) |
305 | + .constraints(IntentSynchronizer.CONSTRAINTS) | ||
304 | .build(); | 306 | .build(); |
305 | 307 | ||
306 | // Setup the expected intents | 308 | // Setup the expected intents |
... | @@ -371,6 +373,7 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -371,6 +373,7 @@ public class IntentSyncTest extends AbstractIntentTest { |
371 | .treatment(treatmentBuilderNew.build()) | 373 | .treatment(treatmentBuilderNew.build()) |
372 | .ingressPoints(ingressPointsNew) | 374 | .ingressPoints(ingressPointsNew) |
373 | .egressPoint(SW2_ETH1) | 375 | .egressPoint(SW2_ETH1) |
376 | + .constraints(IntentSynchronizer.CONSTRAINTS) | ||
374 | .build(); | 377 | .build(); |
375 | 378 | ||
376 | // Set up test expectation | 379 | // Set up test expectation |
... | @@ -609,6 +612,7 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -609,6 +612,7 @@ public class IntentSyncTest extends AbstractIntentTest { |
609 | .treatment(treatmentBuilder.build()) | 612 | .treatment(treatmentBuilder.build()) |
610 | .ingressPoints(ingressPoints) | 613 | .ingressPoints(ingressPoints) |
611 | .egressPoint(egressPoint) | 614 | .egressPoint(egressPoint) |
615 | + .constraints(IntentSynchronizer.CONSTRAINTS) | ||
612 | .build(); | 616 | .build(); |
613 | return intent; | 617 | return intent; |
614 | } | 618 | } | ... | ... |
... | @@ -40,6 +40,7 @@ import org.onosproject.net.intent.Key; | ... | @@ -40,6 +40,7 @@ import org.onosproject.net.intent.Key; |
40 | import org.onosproject.net.intent.constraint.BandwidthConstraint; | 40 | import org.onosproject.net.intent.constraint.BandwidthConstraint; |
41 | import org.onosproject.net.intent.constraint.LambdaConstraint; | 41 | import org.onosproject.net.intent.constraint.LambdaConstraint; |
42 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; | 42 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; |
43 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
43 | import org.onosproject.net.resource.link.BandwidthResource; | 44 | import org.onosproject.net.resource.link.BandwidthResource; |
44 | import org.onlab.packet.IpPrefix; | 45 | import org.onlab.packet.IpPrefix; |
45 | import org.onlab.packet.MacAddress; | 46 | import org.onlab.packet.MacAddress; |
... | @@ -130,6 +131,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { | ... | @@ -130,6 +131,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { |
130 | required = false, multiValued = false) | 131 | required = false, multiValued = false) |
131 | private String intentKey = null; | 132 | private String intentKey = null; |
132 | 133 | ||
134 | + @Option(name = "--partial", description = "Allow partial installation", | ||
135 | + required = false, multiValued = false) | ||
136 | + private boolean partial = false; | ||
137 | + | ||
133 | 138 | ||
134 | // Treatments | 139 | // Treatments |
135 | @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", | 140 | @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", |
... | @@ -350,6 +355,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { | ... | @@ -350,6 +355,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { |
350 | } | 355 | } |
351 | constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL)); | 356 | constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL)); |
352 | 357 | ||
358 | + if (partial) { | ||
359 | + constraints.add(new PartialFailureConstraint()); | ||
360 | + } | ||
361 | + | ||
353 | return constraints; | 362 | return constraints; |
354 | } | 363 | } |
355 | 364 | ... | ... |
core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.net.intent.constraint; | ||
17 | + | ||
18 | +import org.onosproject.net.Link; | ||
19 | +import org.onosproject.net.Path; | ||
20 | +import org.onosproject.net.intent.ConnectivityIntent; | ||
21 | +import org.onosproject.net.intent.Constraint; | ||
22 | +import org.onosproject.net.intent.Intent; | ||
23 | +import org.onosproject.net.resource.link.LinkResourceService; | ||
24 | + | ||
25 | +/** | ||
26 | + * A constraint that allows intents that can only be partially compiled | ||
27 | + * (i.e. MultiPointToSinglePointIntent or SinglePointToMultiPointIntent) | ||
28 | + * to be installed when some endpoints or paths are not found. | ||
29 | + */ | ||
30 | +public class PartialFailureConstraint implements Constraint { | ||
31 | + @Override | ||
32 | + public double cost(Link link, LinkResourceService resourceService) { | ||
33 | + return 1; | ||
34 | + } | ||
35 | + | ||
36 | + @Override | ||
37 | + public boolean validate(Path path, LinkResourceService resourceService) { | ||
38 | + return true; | ||
39 | + } | ||
40 | + | ||
41 | + public static boolean intentAllowsPartialFailure(Intent intent) { | ||
42 | + if (intent instanceof ConnectivityIntent) { | ||
43 | + ConnectivityIntent connectivityIntent = (ConnectivityIntent) intent; | ||
44 | + return connectivityIntent.constraints().stream() | ||
45 | + .anyMatch(c -> c instanceof PartialFailureConstraint); | ||
46 | + } | ||
47 | + return false; | ||
48 | + } | ||
49 | +} |
... | @@ -63,6 +63,7 @@ import static java.util.concurrent.Executors.newFixedThreadPool; | ... | @@ -63,6 +63,7 @@ import static java.util.concurrent.Executors.newFixedThreadPool; |
63 | import static java.util.concurrent.Executors.newSingleThreadExecutor; | 63 | import static java.util.concurrent.Executors.newSingleThreadExecutor; |
64 | import static org.onlab.util.Tools.groupedThreads; | 64 | import static org.onlab.util.Tools.groupedThreads; |
65 | import static org.onosproject.net.intent.IntentState.*; | 65 | import static org.onosproject.net.intent.IntentState.*; |
66 | +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; | ||
66 | import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase; | 67 | import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase; |
67 | import static org.onosproject.security.AppGuard.checkPermission; | 68 | import static org.onosproject.security.AppGuard.checkPermission; |
68 | import static org.slf4j.LoggerFactory.getLogger; | 69 | import static org.slf4j.LoggerFactory.getLogger; |
... | @@ -85,6 +86,8 @@ public class IntentManager | ... | @@ -85,6 +86,8 @@ public class IntentManager |
85 | 86 | ||
86 | private static final EnumSet<IntentState> RECOMPILE | 87 | private static final EnumSet<IntentState> RECOMPILE |
87 | = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ); | 88 | = EnumSet.of(INSTALL_REQ, FAILED, WITHDRAW_REQ); |
89 | + private static final EnumSet<IntentState> WITHDRAW | ||
90 | + = EnumSet.of(WITHDRAW_REQ, WITHDRAWING, WITHDRAWN); | ||
88 | 91 | ||
89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 92 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
90 | protected CoreService coreService; | 93 | protected CoreService coreService; |
... | @@ -252,16 +255,15 @@ public class IntentManager | ... | @@ -252,16 +255,15 @@ public class IntentManager |
252 | submit(intent); | 255 | submit(intent); |
253 | } | 256 | } |
254 | 257 | ||
255 | - if (compileAllFailed) { | 258 | + // If required, compile all currently failed intents. |
256 | - // If required, compile all currently failed intents. | 259 | + for (Intent intent : getIntents()) { |
257 | - for (Intent intent : getIntents()) { | 260 | + IntentState state = getIntentState(intent.key()); |
258 | - IntentState state = getIntentState(intent.key()); | 261 | + if ((compileAllFailed && RECOMPILE.contains(state)) |
259 | - if (RECOMPILE.contains(state)) { | 262 | + || intentAllowsPartialFailure(intent)) { |
260 | - if (state == WITHDRAW_REQ) { | 263 | + if (WITHDRAW.contains(state)) { |
261 | - withdraw(intent); | 264 | + withdraw(intent); |
262 | - } else { | 265 | + } else { |
263 | - submit(intent); | 266 | + submit(intent); |
264 | - } | ||
265 | } | 267 | } |
266 | } | 268 | } |
267 | } | 269 | } | ... | ... |
... | @@ -276,31 +276,28 @@ public class ObjectiveTracker implements ObjectiveTrackerService { | ... | @@ -276,31 +276,28 @@ public class ObjectiveTracker implements ObjectiveTrackerService { |
276 | delegate.triggerCompile(Collections.emptySet(), true); | 276 | delegate.triggerCompile(Collections.emptySet(), true); |
277 | 277 | ||
278 | } else { | 278 | } else { |
279 | - Set<Key> toBeRecompiled = new HashSet<>(); | 279 | + Set<Key> intentsToRecompile = new HashSet<>(); |
280 | - boolean recompileOnly = true; | 280 | + boolean dontRecompileAllFailedIntents = true; |
281 | 281 | ||
282 | // Scan through the list of reasons and keep accruing all | 282 | // Scan through the list of reasons and keep accruing all |
283 | // intents that need to be recompiled. | 283 | // intents that need to be recompiled. |
284 | for (Event reason : event.reasons()) { | 284 | for (Event reason : event.reasons()) { |
285 | if (reason instanceof LinkEvent) { | 285 | if (reason instanceof LinkEvent) { |
286 | LinkEvent linkEvent = (LinkEvent) reason; | 286 | LinkEvent linkEvent = (LinkEvent) reason; |
287 | - if (linkEvent.type() == LINK_REMOVED | 287 | + final LinkKey linkKey = linkKey(linkEvent.subject()); |
288 | - || (linkEvent.type() == LINK_UPDATED && | 288 | + synchronized (intentsByLink) { |
289 | - linkEvent.subject().isDurable())) { | 289 | + Set<Key> intentKeys = intentsByLink.get(linkKey); |
290 | - final LinkKey linkKey = linkKey(linkEvent.subject()); | 290 | + log.debug("recompile triggered by LinkEvent {} ({}) for {}", |
291 | - synchronized (intentsByLink) { | 291 | + linkKey, linkEvent.type(), intentKeys); |
292 | - Set<Key> intentKeys = intentsByLink.get(linkKey); | 292 | + intentsToRecompile.addAll(intentKeys); |
293 | - log.debug("recompile triggered by LinkDown {} {}", linkKey, intentKeys); | ||
294 | - toBeRecompiled.addAll(intentKeys); | ||
295 | - } | ||
296 | } | 293 | } |
297 | - recompileOnly = recompileOnly && | 294 | + dontRecompileAllFailedIntents = dontRecompileAllFailedIntents && |
298 | (linkEvent.type() == LINK_REMOVED || | 295 | (linkEvent.type() == LINK_REMOVED || |
299 | (linkEvent.type() == LINK_UPDATED && | 296 | (linkEvent.type() == LINK_UPDATED && |
300 | linkEvent.subject().isDurable())); | 297 | linkEvent.subject().isDurable())); |
301 | } | 298 | } |
302 | } | 299 | } |
303 | - delegate.triggerCompile(toBeRecompiled, !recompileOnly); | 300 | + delegate.triggerCompile(intentsToRecompile, !dontRecompileAllFailedIntents); |
304 | } | 301 | } |
305 | } | 302 | } |
306 | } | 303 | } | ... | ... |
... | @@ -26,13 +26,14 @@ import org.onosproject.net.ConnectPoint; | ... | @@ -26,13 +26,14 @@ import org.onosproject.net.ConnectPoint; |
26 | import org.onosproject.net.DeviceId; | 26 | import org.onosproject.net.DeviceId; |
27 | import org.onosproject.net.Link; | 27 | import org.onosproject.net.Link; |
28 | import org.onosproject.net.Path; | 28 | import org.onosproject.net.Path; |
29 | +import org.onosproject.net.device.DeviceService; | ||
29 | import org.onosproject.net.intent.Intent; | 30 | import org.onosproject.net.intent.Intent; |
30 | import org.onosproject.net.intent.IntentCompiler; | 31 | import org.onosproject.net.intent.IntentCompiler; |
32 | +import org.onosproject.net.intent.IntentException; | ||
31 | import org.onosproject.net.intent.IntentExtensionService; | 33 | import org.onosproject.net.intent.IntentExtensionService; |
32 | import org.onosproject.net.intent.LinkCollectionIntent; | 34 | import org.onosproject.net.intent.LinkCollectionIntent; |
33 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; | 35 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
34 | import org.onosproject.net.intent.PointToPointIntent; | 36 | import org.onosproject.net.intent.PointToPointIntent; |
35 | -import org.onosproject.net.intent.impl.PathNotFoundException; | ||
36 | import org.onosproject.net.resource.link.LinkResourceAllocations; | 37 | import org.onosproject.net.resource.link.LinkResourceAllocations; |
37 | import org.onosproject.net.topology.PathService; | 38 | import org.onosproject.net.topology.PathService; |
38 | 39 | ||
... | @@ -42,6 +43,9 @@ import java.util.List; | ... | @@ -42,6 +43,9 @@ import java.util.List; |
42 | import java.util.Map; | 43 | import java.util.Map; |
43 | import java.util.Set; | 44 | import java.util.Set; |
44 | 45 | ||
46 | +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; | ||
47 | + | ||
48 | + | ||
45 | /** | 49 | /** |
46 | * An intent compiler for | 50 | * An intent compiler for |
47 | * {@link org.onosproject.net.intent.MultiPointToSinglePointIntent}. | 51 | * {@link org.onosproject.net.intent.MultiPointToSinglePointIntent}. |
... | @@ -56,6 +60,9 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -56,6 +60,9 @@ public class MultiPointToSinglePointIntentCompiler |
56 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 60 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
57 | protected PathService pathService; | 61 | protected PathService pathService; |
58 | 62 | ||
63 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
64 | + protected DeviceService deviceService; | ||
65 | + | ||
59 | @Activate | 66 | @Activate |
60 | public void activate() { | 67 | public void activate() { |
61 | intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this); | 68 | intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this); |
... | @@ -72,25 +79,46 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -72,25 +79,46 @@ public class MultiPointToSinglePointIntentCompiler |
72 | Map<DeviceId, Link> links = new HashMap<>(); | 79 | Map<DeviceId, Link> links = new HashMap<>(); |
73 | ConnectPoint egressPoint = intent.egressPoint(); | 80 | ConnectPoint egressPoint = intent.egressPoint(); |
74 | 81 | ||
82 | + final boolean allowMissingPaths = intentAllowsPartialFailure(intent); | ||
83 | + boolean partialTree = false; | ||
84 | + boolean anyMissingPaths = false; | ||
75 | for (ConnectPoint ingressPoint : intent.ingressPoints()) { | 85 | for (ConnectPoint ingressPoint : intent.ingressPoints()) { |
76 | if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { | 86 | if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { |
87 | + if (deviceService.isAvailable(ingressPoint.deviceId())) { | ||
88 | + partialTree = true; | ||
89 | + } else { | ||
90 | + anyMissingPaths = true; | ||
91 | + } | ||
92 | + | ||
77 | continue; | 93 | continue; |
78 | } | 94 | } |
95 | + | ||
79 | Path path = getPath(ingressPoint, intent.egressPoint()); | 96 | Path path = getPath(ingressPoint, intent.egressPoint()); |
80 | - for (Link link : path.links()) { | 97 | + if (path != null) { |
81 | - if (links.containsKey(link.src().deviceId())) { | 98 | + partialTree = true; |
82 | - // We've already reached the existing tree with the first | 99 | + |
83 | - // part of this path. Add the merging point with different | 100 | + for (Link link : path.links()) { |
84 | - // incoming port, but don't add the remainder of the path | 101 | + if (links.containsKey(link.src().deviceId())) { |
85 | - // in case it differs from the path we already have. | 102 | + // We've already reached the existing tree with the first |
103 | + // part of this path. Add the merging point with different | ||
104 | + // incoming port, but don't add the remainder of the path | ||
105 | + // in case it differs from the path we already have. | ||
106 | + links.put(link.src().deviceId(), link); | ||
107 | + break; | ||
108 | + } | ||
86 | links.put(link.src().deviceId(), link); | 109 | links.put(link.src().deviceId(), link); |
87 | - break; | ||
88 | } | 110 | } |
89 | - | 111 | + } else { |
90 | - links.put(link.src().deviceId(), link); | 112 | + anyMissingPaths = true; |
91 | } | 113 | } |
92 | } | 114 | } |
93 | 115 | ||
116 | + if (!partialTree) { | ||
117 | + throw new IntentException("Could not find any paths between ingress and egress points."); | ||
118 | + } else if (!allowMissingPaths && anyMissingPaths) { | ||
119 | + throw new IntentException("Missing some paths between ingress and egress ports."); | ||
120 | + } | ||
121 | + | ||
94 | Intent result = LinkCollectionIntent.builder() | 122 | Intent result = LinkCollectionIntent.builder() |
95 | .appId(intent.appId()) | 123 | .appId(intent.appId()) |
96 | .selector(intent.selector()) | 124 | .selector(intent.selector()) |
... | @@ -111,12 +139,11 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -111,12 +139,11 @@ public class MultiPointToSinglePointIntentCompiler |
111 | * @param one start of the path | 139 | * @param one start of the path |
112 | * @param two end of the path | 140 | * @param two end of the path |
113 | * @return Path between the two | 141 | * @return Path between the two |
114 | - * @throws org.onosproject.net.intent.impl.PathNotFoundException if a path cannot be found | ||
115 | */ | 142 | */ |
116 | private Path getPath(ConnectPoint one, ConnectPoint two) { | 143 | private Path getPath(ConnectPoint one, ConnectPoint two) { |
117 | Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId()); | 144 | Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId()); |
118 | if (paths.isEmpty()) { | 145 | if (paths.isEmpty()) { |
119 | - throw new PathNotFoundException(one.elementId(), two.elementId()); | 146 | + return null; |
120 | } | 147 | } |
121 | // TODO: let's be more intelligent about this eventually | 148 | // TODO: let's be more intelligent about this eventually |
122 | return paths.iterator().next(); | 149 | return paths.iterator().next(); | ... | ... |
... | @@ -20,8 +20,10 @@ import org.junit.Test; | ... | @@ -20,8 +20,10 @@ import org.junit.Test; |
20 | import org.onosproject.TestApplicationId; | 20 | import org.onosproject.TestApplicationId; |
21 | import org.onosproject.core.ApplicationId; | 21 | import org.onosproject.core.ApplicationId; |
22 | import org.onosproject.net.ConnectPoint; | 22 | import org.onosproject.net.ConnectPoint; |
23 | +import org.onosproject.net.DeviceId; | ||
23 | import org.onosproject.net.ElementId; | 24 | import org.onosproject.net.ElementId; |
24 | import org.onosproject.net.Path; | 25 | import org.onosproject.net.Path; |
26 | +import org.onosproject.net.device.DeviceServiceAdapter; | ||
25 | import org.onosproject.net.flow.TrafficSelector; | 27 | import org.onosproject.net.flow.TrafficSelector; |
26 | import org.onosproject.net.flow.TrafficTreatment; | 28 | import org.onosproject.net.flow.TrafficTreatment; |
27 | import org.onosproject.net.intent.AbstractIntentTest; | 29 | import org.onosproject.net.intent.AbstractIntentTest; |
... | @@ -92,6 +94,16 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes | ... | @@ -92,6 +94,16 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes |
92 | } | 94 | } |
93 | 95 | ||
94 | /** | 96 | /** |
97 | + * Mocks the device service so that a device appears available in the test. | ||
98 | + */ | ||
99 | + private static class MockDeviceService extends DeviceServiceAdapter { | ||
100 | + @Override | ||
101 | + public boolean isAvailable(DeviceId deviceId) { | ||
102 | + return true; | ||
103 | + } | ||
104 | + } | ||
105 | + | ||
106 | + /** | ||
95 | * Creates a MultiPointToSinglePoint intent for a group of ingress points | 107 | * Creates a MultiPointToSinglePoint intent for a group of ingress points |
96 | * and an egress point. | 108 | * and an egress point. |
97 | * | 109 | * |
... | @@ -126,6 +138,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes | ... | @@ -126,6 +138,7 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes |
126 | MultiPointToSinglePointIntentCompiler compiler = | 138 | MultiPointToSinglePointIntentCompiler compiler = |
127 | new MultiPointToSinglePointIntentCompiler(); | 139 | new MultiPointToSinglePointIntentCompiler(); |
128 | compiler.pathService = new MockPathService(hops); | 140 | compiler.pathService = new MockPathService(hops); |
141 | + compiler.deviceService = new MockDeviceService(); | ||
129 | return compiler; | 142 | return compiler; |
130 | } | 143 | } |
131 | 144 | ... | ... |
... | @@ -157,6 +157,7 @@ import org.onosproject.net.intent.constraint.LambdaConstraint; | ... | @@ -157,6 +157,7 @@ import org.onosproject.net.intent.constraint.LambdaConstraint; |
157 | import org.onosproject.net.intent.constraint.LatencyConstraint; | 157 | import org.onosproject.net.intent.constraint.LatencyConstraint; |
158 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; | 158 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; |
159 | import org.onosproject.net.intent.constraint.ObstacleConstraint; | 159 | import org.onosproject.net.intent.constraint.ObstacleConstraint; |
160 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
160 | import org.onosproject.net.intent.constraint.WaypointConstraint; | 161 | import org.onosproject.net.intent.constraint.WaypointConstraint; |
161 | import org.onosproject.net.link.DefaultLinkDescription; | 162 | import org.onosproject.net.link.DefaultLinkDescription; |
162 | import org.onosproject.net.newresource.DefaultResource; | 163 | import org.onosproject.net.newresource.DefaultResource; |
... | @@ -412,6 +413,7 @@ public final class KryoNamespaces { | ... | @@ -412,6 +413,7 @@ public final class KryoNamespaces { |
412 | ObstacleConstraint.class, | 413 | ObstacleConstraint.class, |
413 | AnnotationConstraint.class, | 414 | AnnotationConstraint.class, |
414 | BooleanConstraint.class, | 415 | BooleanConstraint.class, |
416 | + PartialFailureConstraint.class, | ||
415 | IntentOperation.class, | 417 | IntentOperation.class, |
416 | FlowRuleExtPayLoad.class, | 418 | FlowRuleExtPayLoad.class, |
417 | Frequency.class, | 419 | Frequency.class, | ... | ... |
-
Please register or login to post a comment