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 Change-Id: I32eaa198fae1dfba021d9251c8f855573f0e1d7d
Showing
9 changed files
with
152 additions
and
46 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 | ||
... | @@ -427,6 +432,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -427,6 +432,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
427 | .ingressPoints(ingressPoints) | 432 | .ingressPoints(ingressPoints) |
428 | .egressPoint(egressPoint) | 433 | .egressPoint(egressPoint) |
429 | .priority(priority) | 434 | .priority(priority) |
435 | + .constraints(CONSTRAINTS) | ||
430 | .build(); | 436 | .build(); |
431 | 437 | ||
432 | log.trace("Generates ConnectivityInternetToHost intent {}", intent); | 438 | log.trace("Generates ConnectivityInternetToHost intent {}", intent); |
... | @@ -925,6 +931,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -925,6 +931,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
925 | .ingressPoints(ingressPoints) | 931 | .ingressPoints(ingressPoints) |
926 | .egressPoint(dstConnectPoint) | 932 | .egressPoint(dstConnectPoint) |
927 | .priority(priority) | 933 | .priority(priority) |
934 | + .constraints(CONSTRAINTS) | ||
928 | .build(); | 935 | .build(); |
929 | 936 | ||
930 | log.trace("Generates ConnectivityHostToHost = {} ", intent); | 937 | log.trace("Generates ConnectivityHostToHost = {} ", intent); |
... | @@ -952,6 +959,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -952,6 +959,7 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
952 | .ingressPoints(ingressPoints) | 959 | .ingressPoints(ingressPoints) |
953 | .egressPoint(existingIntent.egressPoint()) | 960 | .egressPoint(existingIntent.egressPoint()) |
954 | .priority(existingIntent.priority()) | 961 | .priority(existingIntent.priority()) |
962 | + .constraints(CONSTRAINTS) | ||
955 | .build(); | 963 | .build(); |
956 | 964 | ||
957 | log.trace("Update an existing MultiPointToSinglePointIntent " | 965 | 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 | } | ... | ... |
... | @@ -39,6 +39,7 @@ import org.onosproject.net.intent.Key; | ... | @@ -39,6 +39,7 @@ import org.onosproject.net.intent.Key; |
39 | import org.onosproject.net.intent.constraint.BandwidthConstraint; | 39 | import org.onosproject.net.intent.constraint.BandwidthConstraint; |
40 | import org.onosproject.net.intent.constraint.LambdaConstraint; | 40 | import org.onosproject.net.intent.constraint.LambdaConstraint; |
41 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; | 41 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; |
42 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
42 | import org.onosproject.net.resource.link.BandwidthResource; | 43 | import org.onosproject.net.resource.link.BandwidthResource; |
43 | import org.onlab.packet.IpPrefix; | 44 | import org.onlab.packet.IpPrefix; |
44 | import org.onlab.packet.MacAddress; | 45 | import org.onlab.packet.MacAddress; |
... | @@ -125,6 +126,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { | ... | @@ -125,6 +126,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { |
125 | required = false, multiValued = false) | 126 | required = false, multiValued = false) |
126 | private String intentKey = null; | 127 | private String intentKey = null; |
127 | 128 | ||
129 | + @Option(name = "--partial", description = "Allow partial installation", | ||
130 | + required = false, multiValued = false) | ||
131 | + private boolean partial = false; | ||
132 | + | ||
128 | 133 | ||
129 | // Treatments | 134 | // Treatments |
130 | @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", | 135 | @Option(name = "--setEthSrc", description = "Rewrite Source MAC Address", |
... | @@ -318,6 +323,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { | ... | @@ -318,6 +323,10 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand { |
318 | } | 323 | } |
319 | constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL)); | 324 | constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL)); |
320 | 325 | ||
326 | + if (partial) { | ||
327 | + constraints.add(new PartialFailureConstraint()); | ||
328 | + } | ||
329 | + | ||
321 | return constraints; | 330 | return constraints; |
322 | } | 331 | } |
323 | 332 | ... | ... |
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 | +} |
... | @@ -25,8 +25,8 @@ import org.apache.felix.scr.annotations.Service; | ... | @@ -25,8 +25,8 @@ import org.apache.felix.scr.annotations.Service; |
25 | import org.onosproject.core.CoreService; | 25 | import org.onosproject.core.CoreService; |
26 | import org.onosproject.core.IdGenerator; | 26 | import org.onosproject.core.IdGenerator; |
27 | import org.onosproject.core.Permission; | 27 | import org.onosproject.core.Permission; |
28 | -import org.onosproject.event.ListenerRegistry; | ||
29 | import org.onosproject.event.EventDeliveryService; | 28 | import org.onosproject.event.EventDeliveryService; |
29 | +import org.onosproject.event.ListenerRegistry; | ||
30 | import org.onosproject.net.flow.FlowRule; | 30 | import org.onosproject.net.flow.FlowRule; |
31 | import org.onosproject.net.flow.FlowRuleOperations; | 31 | import org.onosproject.net.flow.FlowRuleOperations; |
32 | import org.onosproject.net.flow.FlowRuleOperationsContext; | 32 | import org.onosproject.net.flow.FlowRuleOperationsContext; |
... | @@ -64,9 +64,10 @@ import static java.util.concurrent.Executors.newFixedThreadPool; | ... | @@ -64,9 +64,10 @@ import static java.util.concurrent.Executors.newFixedThreadPool; |
64 | import static java.util.concurrent.Executors.newSingleThreadExecutor; | 64 | import static java.util.concurrent.Executors.newSingleThreadExecutor; |
65 | import static org.onlab.util.Tools.groupedThreads; | 65 | import static org.onlab.util.Tools.groupedThreads; |
66 | import static org.onosproject.net.intent.IntentState.*; | 66 | import static org.onosproject.net.intent.IntentState.*; |
67 | +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; | ||
67 | import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase; | 68 | import static org.onosproject.net.intent.impl.phase.IntentProcessPhase.newInitialPhase; |
68 | -import static org.slf4j.LoggerFactory.getLogger; | ||
69 | import static org.onosproject.security.AppGuard.checkPermission; | 69 | import static org.onosproject.security.AppGuard.checkPermission; |
70 | +import static org.slf4j.LoggerFactory.getLogger; | ||
70 | 71 | ||
71 | 72 | ||
72 | /** | 73 | /** |
... | @@ -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 | private final ListenerRegistry<IntentEvent, IntentListener> | 92 | private final ListenerRegistry<IntentEvent, IntentListener> |
90 | listenerRegistry = new ListenerRegistry<>(); | 93 | listenerRegistry = new ListenerRegistry<>(); |
... | @@ -282,19 +285,18 @@ public class IntentManager | ... | @@ -282,19 +285,18 @@ public class IntentManager |
282 | submit(intent); | 285 | submit(intent); |
283 | } | 286 | } |
284 | 287 | ||
285 | - if (compileAllFailed) { | ||
286 | // If required, compile all currently failed intents. | 288 | // If required, compile all currently failed intents. |
287 | for (Intent intent : getIntents()) { | 289 | for (Intent intent : getIntents()) { |
288 | IntentState state = getIntentState(intent.key()); | 290 | IntentState state = getIntentState(intent.key()); |
289 | - if (RECOMPILE.contains(state)) { | 291 | + if ((compileAllFailed && RECOMPILE.contains(state)) |
290 | - if (state == WITHDRAW_REQ) { | 292 | + || intentAllowsPartialFailure(intent)) { |
293 | + if (WITHDRAW.contains(state)) { | ||
291 | withdraw(intent); | 294 | withdraw(intent); |
292 | } else { | 295 | } else { |
293 | submit(intent); | 296 | submit(intent); |
294 | } | 297 | } |
295 | } | 298 | } |
296 | } | 299 | } |
297 | - } | ||
298 | 300 | ||
299 | //FIXME | 301 | //FIXME |
300 | // for (ApplicationId appId : batches.keySet()) { | 302 | // for (ApplicationId appId : batches.keySet()) { | ... | ... |
... | @@ -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 | ||
288 | - || (linkEvent.type() == LINK_UPDATED && | ||
289 | - linkEvent.subject().isDurable())) { | ||
290 | final LinkKey linkKey = linkKey(linkEvent.subject()); | 287 | final LinkKey linkKey = linkKey(linkEvent.subject()); |
291 | synchronized (intentsByLink) { | 288 | synchronized (intentsByLink) { |
292 | Set<Key> intentKeys = intentsByLink.get(linkKey); | 289 | Set<Key> intentKeys = intentsByLink.get(linkKey); |
293 | - log.debug("recompile triggered by LinkDown {} {}", linkKey, intentKeys); | 290 | + log.debug("recompile triggered by LinkEvent {} ({}) for {}", |
294 | - toBeRecompiled.addAll(intentKeys); | 291 | + linkKey, linkEvent.type(), intentKeys); |
292 | + intentsToRecompile.addAll(intentKeys); | ||
295 | } | 293 | } |
296 | - } | 294 | + dontRecompileAllFailedIntents = dontRecompileAllFailedIntents && |
297 | - recompileOnly = recompileOnly && | ||
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 | } | ... | ... |
... | @@ -15,12 +15,8 @@ | ... | @@ -15,12 +15,8 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.intent.impl.compiler; | 16 | package org.onosproject.net.intent.impl.compiler; |
17 | 17 | ||
18 | -import java.util.Collections; | 18 | +import com.google.common.collect.ImmutableSet; |
19 | -import java.util.HashMap; | 19 | +import com.google.common.collect.Sets; |
20 | -import java.util.List; | ||
21 | -import java.util.Map; | ||
22 | -import java.util.Set; | ||
23 | - | ||
24 | import org.apache.felix.scr.annotations.Activate; | 20 | import org.apache.felix.scr.annotations.Activate; |
25 | import org.apache.felix.scr.annotations.Component; | 21 | import org.apache.felix.scr.annotations.Component; |
26 | import org.apache.felix.scr.annotations.Deactivate; | 22 | import org.apache.felix.scr.annotations.Deactivate; |
... | @@ -30,20 +26,25 @@ import org.onosproject.net.ConnectPoint; | ... | @@ -30,20 +26,25 @@ import org.onosproject.net.ConnectPoint; |
30 | import org.onosproject.net.DeviceId; | 26 | import org.onosproject.net.DeviceId; |
31 | import org.onosproject.net.Link; | 27 | import org.onosproject.net.Link; |
32 | import org.onosproject.net.Path; | 28 | import org.onosproject.net.Path; |
29 | +import org.onosproject.net.device.DeviceService; | ||
33 | import org.onosproject.net.intent.Intent; | 30 | import org.onosproject.net.intent.Intent; |
34 | import org.onosproject.net.intent.IntentCompiler; | 31 | import org.onosproject.net.intent.IntentCompiler; |
32 | +import org.onosproject.net.intent.IntentException; | ||
35 | import org.onosproject.net.intent.IntentExtensionService; | 33 | import org.onosproject.net.intent.IntentExtensionService; |
36 | import org.onosproject.net.intent.LinkCollectionIntent; | 34 | import org.onosproject.net.intent.LinkCollectionIntent; |
37 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; | 35 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
38 | import org.onosproject.net.intent.PointToPointIntent; | 36 | import org.onosproject.net.intent.PointToPointIntent; |
39 | -import org.onosproject.net.intent.impl.PathNotFoundException; | ||
40 | import org.onosproject.net.resource.link.LinkResourceAllocations; | 37 | import org.onosproject.net.resource.link.LinkResourceAllocations; |
41 | import org.onosproject.net.topology.PathService; | 38 | import org.onosproject.net.topology.PathService; |
42 | 39 | ||
43 | -import com.google.common.collect.ImmutableSet; | 40 | +import java.util.Collections; |
44 | -import com.google.common.collect.Sets; | 41 | +import java.util.HashMap; |
42 | +import java.util.List; | ||
43 | +import java.util.Map; | ||
44 | +import java.util.Set; | ||
45 | 45 | ||
46 | import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; | 46 | import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; |
47 | +import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; | ||
47 | 48 | ||
48 | /** | 49 | /** |
49 | * An intent compiler for | 50 | * An intent compiler for |
... | @@ -59,6 +60,9 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -59,6 +60,9 @@ public class MultiPointToSinglePointIntentCompiler |
59 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 60 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
60 | protected PathService pathService; | 61 | protected PathService pathService; |
61 | 62 | ||
63 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
64 | + protected DeviceService deviceService; | ||
65 | + | ||
62 | @Activate | 66 | @Activate |
63 | public void activate() { | 67 | public void activate() { |
64 | intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this); | 68 | intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this); |
... | @@ -76,12 +80,22 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -76,12 +80,22 @@ public class MultiPointToSinglePointIntentCompiler |
76 | Map<DeviceId, Link> edgeLinks = new HashMap<>(); | 80 | Map<DeviceId, Link> edgeLinks = new HashMap<>(); |
77 | ConnectPoint egressPoint = intent.egressPoint(); | 81 | ConnectPoint egressPoint = intent.egressPoint(); |
78 | 82 | ||
83 | + final boolean allowMissingPaths = intentAllowsPartialFailure(intent); | ||
84 | + boolean partialTree = false; | ||
85 | + boolean anyMissingPaths = false; | ||
79 | for (ConnectPoint ingressPoint : intent.ingressPoints()) { | 86 | for (ConnectPoint ingressPoint : intent.ingressPoints()) { |
80 | if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { | 87 | if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { |
88 | + if (deviceService.isAvailable(ingressPoint.deviceId())) { | ||
89 | + partialTree = true; | ||
81 | edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true)); | 90 | edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true)); |
82 | edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false)); | 91 | edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false)); |
83 | } else { | 92 | } else { |
93 | + anyMissingPaths = true; | ||
94 | + } | ||
95 | + } else { | ||
84 | Path path = getPath(ingressPoint, intent.egressPoint()); | 96 | Path path = getPath(ingressPoint, intent.egressPoint()); |
97 | + if (path != null) { | ||
98 | + partialTree = true; | ||
85 | for (Link link : path.links()) { | 99 | for (Link link : path.links()) { |
86 | if (links.containsKey(link.src().deviceId())) { | 100 | if (links.containsKey(link.src().deviceId())) { |
87 | // We've already reached the existing tree with the first | 101 | // We've already reached the existing tree with the first |
... | @@ -94,9 +108,18 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -94,9 +108,18 @@ public class MultiPointToSinglePointIntentCompiler |
94 | 108 | ||
95 | links.put(link.src().deviceId(), link); | 109 | links.put(link.src().deviceId(), link); |
96 | } | 110 | } |
111 | + } else { | ||
112 | + anyMissingPaths = true; | ||
113 | + } | ||
97 | } | 114 | } |
98 | } | 115 | } |
99 | 116 | ||
117 | + if (!partialTree) { | ||
118 | + throw new IntentException("Could not find any paths between ingress and egress points."); | ||
119 | + } else if (!allowMissingPaths && anyMissingPaths) { | ||
120 | + throw new IntentException("Missing some paths between ingress and egress ports."); | ||
121 | + } | ||
122 | + | ||
100 | Set<Link> allLinks = Sets.newHashSet(links.values()); | 123 | Set<Link> allLinks = Sets.newHashSet(links.values()); |
101 | allLinks.addAll(edgeLinks.values()); | 124 | allLinks.addAll(edgeLinks.values()); |
102 | Intent result = LinkCollectionIntent.builder() | 125 | Intent result = LinkCollectionIntent.builder() |
... | @@ -119,12 +142,11 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -119,12 +142,11 @@ public class MultiPointToSinglePointIntentCompiler |
119 | * @param one start of the path | 142 | * @param one start of the path |
120 | * @param two end of the path | 143 | * @param two end of the path |
121 | * @return Path between the two | 144 | * @return Path between the two |
122 | - * @throws org.onosproject.net.intent.impl.PathNotFoundException if a path cannot be found | ||
123 | */ | 145 | */ |
124 | private Path getPath(ConnectPoint one, ConnectPoint two) { | 146 | private Path getPath(ConnectPoint one, ConnectPoint two) { |
125 | Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId()); | 147 | Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId()); |
126 | if (paths.isEmpty()) { | 148 | if (paths.isEmpty()) { |
127 | - throw new PathNotFoundException(one.elementId(), two.elementId()); | 149 | + return null; |
128 | } | 150 | } |
129 | // TODO: let's be more intelligent about this eventually | 151 | // TODO: let's be more intelligent about this eventually |
130 | return paths.iterator().next(); | 152 | return paths.iterator().next(); | ... | ... |
... | @@ -15,17 +15,15 @@ | ... | @@ -15,17 +15,15 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.net.intent.impl.compiler; | 16 | package org.onosproject.net.intent.impl.compiler; |
17 | 17 | ||
18 | -import java.util.HashSet; | ||
19 | -import java.util.List; | ||
20 | -import java.util.Set; | ||
21 | - | ||
22 | import org.hamcrest.Matchers; | 18 | import org.hamcrest.Matchers; |
23 | import org.junit.Test; | 19 | import org.junit.Test; |
24 | import org.onosproject.TestApplicationId; | 20 | import org.onosproject.TestApplicationId; |
25 | import org.onosproject.core.ApplicationId; | 21 | import org.onosproject.core.ApplicationId; |
26 | import org.onosproject.net.ConnectPoint; | 22 | import org.onosproject.net.ConnectPoint; |
23 | +import org.onosproject.net.DeviceId; | ||
27 | import org.onosproject.net.ElementId; | 24 | import org.onosproject.net.ElementId; |
28 | import org.onosproject.net.Path; | 25 | import org.onosproject.net.Path; |
26 | +import org.onosproject.net.device.DeviceServiceAdapter; | ||
29 | import org.onosproject.net.flow.TrafficSelector; | 27 | import org.onosproject.net.flow.TrafficSelector; |
30 | import org.onosproject.net.flow.TrafficTreatment; | 28 | import org.onosproject.net.flow.TrafficTreatment; |
31 | import org.onosproject.net.intent.AbstractIntentTest; | 29 | import org.onosproject.net.intent.AbstractIntentTest; |
... | @@ -36,6 +34,10 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent; | ... | @@ -36,6 +34,10 @@ import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
36 | import org.onosproject.net.topology.LinkWeight; | 34 | import org.onosproject.net.topology.LinkWeight; |
37 | import org.onosproject.net.topology.PathService; | 35 | import org.onosproject.net.topology.PathService; |
38 | 36 | ||
37 | +import java.util.HashSet; | ||
38 | +import java.util.List; | ||
39 | +import java.util.Set; | ||
40 | + | ||
39 | import static org.hamcrest.CoreMatchers.instanceOf; | 41 | import static org.hamcrest.CoreMatchers.instanceOf; |
40 | import static org.hamcrest.CoreMatchers.notNullValue; | 42 | import static org.hamcrest.CoreMatchers.notNullValue; |
41 | import static org.hamcrest.MatcherAssert.assertThat; | 43 | import static org.hamcrest.MatcherAssert.assertThat; |
... | @@ -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 | ... | ... |
... | @@ -151,6 +151,7 @@ import org.onosproject.net.intent.constraint.LambdaConstraint; | ... | @@ -151,6 +151,7 @@ import org.onosproject.net.intent.constraint.LambdaConstraint; |
151 | import org.onosproject.net.intent.constraint.LatencyConstraint; | 151 | import org.onosproject.net.intent.constraint.LatencyConstraint; |
152 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; | 152 | import org.onosproject.net.intent.constraint.LinkTypeConstraint; |
153 | import org.onosproject.net.intent.constraint.ObstacleConstraint; | 153 | import org.onosproject.net.intent.constraint.ObstacleConstraint; |
154 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
154 | import org.onosproject.net.intent.constraint.WaypointConstraint; | 155 | import org.onosproject.net.intent.constraint.WaypointConstraint; |
155 | import org.onosproject.net.link.DefaultLinkDescription; | 156 | import org.onosproject.net.link.DefaultLinkDescription; |
156 | import org.onosproject.net.packet.DefaultOutboundPacket; | 157 | import org.onosproject.net.packet.DefaultOutboundPacket; |
... | @@ -389,6 +390,7 @@ public final class KryoNamespaces { | ... | @@ -389,6 +390,7 @@ public final class KryoNamespaces { |
389 | ObstacleConstraint.class, | 390 | ObstacleConstraint.class, |
390 | AnnotationConstraint.class, | 391 | AnnotationConstraint.class, |
391 | BooleanConstraint.class, | 392 | BooleanConstraint.class, |
393 | + PartialFailureConstraint.class, | ||
392 | IntentOperation.class, | 394 | IntentOperation.class, |
393 | FlowRuleExtPayLoad.class, | 395 | FlowRuleExtPayLoad.class, |
394 | Frequency.class, | 396 | Frequency.class, | ... | ... |
-
Please register or login to post a comment