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
172 additions
and
66 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,16 +285,15 @@ public class IntentManager | ... | @@ -282,16 +285,15 @@ public class IntentManager |
| 282 | submit(intent); | 285 | submit(intent); |
| 283 | } | 286 | } |
| 284 | 287 | ||
| 285 | - if (compileAllFailed) { | 288 | + // If required, compile all currently failed intents. |
| 286 | - // If required, compile all currently failed intents. | 289 | + for (Intent intent : getIntents()) { |
| 287 | - for (Intent intent : getIntents()) { | 290 | + IntentState state = getIntentState(intent.key()); |
| 288 | - IntentState state = getIntentState(intent.key()); | 291 | + if ((compileAllFailed && RECOMPILE.contains(state)) |
| 289 | - if (RECOMPILE.contains(state)) { | 292 | + || intentAllowsPartialFailure(intent)) { |
| 290 | - if (state == WITHDRAW_REQ) { | 293 | + if (WITHDRAW.contains(state)) { |
| 291 | - withdraw(intent); | 294 | + withdraw(intent); |
| 292 | - } else { | 295 | + } else { |
| 293 | - submit(intent); | 296 | + submit(intent); |
| 294 | - } | ||
| 295 | } | 297 | } |
| 296 | } | 298 | } |
| 297 | } | 299 | } | ... | ... |
| ... | @@ -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 | } | ... | ... |
| ... | @@ -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,27 +80,46 @@ public class MultiPointToSinglePointIntentCompiler | ... | @@ -76,27 +80,46 @@ 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())) { |
| 81 | - edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true)); | 88 | + if (deviceService.isAvailable(ingressPoint.deviceId())) { |
| 82 | - edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false)); | 89 | + partialTree = true; |
| 90 | + edgeLinks.put(ingressPoint.deviceId(), createEdgeLink(ingressPoint, true)); | ||
| 91 | + edgeLinks.put(egressPoint.deviceId(), createEdgeLink(egressPoint, false)); | ||
| 92 | + } else { | ||
| 93 | + anyMissingPaths = true; | ||
| 94 | + } | ||
| 83 | } else { | 95 | } else { |
| 84 | Path path = getPath(ingressPoint, intent.egressPoint()); | 96 | Path path = getPath(ingressPoint, intent.egressPoint()); |
| 85 | - for (Link link : path.links()) { | 97 | + if (path != null) { |
| 86 | - if (links.containsKey(link.src().deviceId())) { | 98 | + partialTree = true; |
| 87 | - // We've already reached the existing tree with the first | 99 | + for (Link link : path.links()) { |
| 88 | - // part of this path. Add the merging point with different | 100 | + if (links.containsKey(link.src().deviceId())) { |
| 89 | - // incoming port, but don't add the remainder of the path | 101 | + // We've already reached the existing tree with the first |
| 90 | - // in case it differs from the path we already have. | 102 | + // part of this path. Add the merging point with different |
| 103 | + // incoming port, but don't add the remainder of the path | ||
| 104 | + // in case it differs from the path we already have. | ||
| 105 | + links.put(link.src().deviceId(), link); | ||
| 106 | + break; | ||
| 107 | + } | ||
| 108 | + | ||
| 91 | links.put(link.src().deviceId(), link); | 109 | links.put(link.src().deviceId(), link); |
| 92 | - break; | ||
| 93 | } | 110 | } |
| 94 | - | 111 | + } else { |
| 95 | - links.put(link.src().deviceId(), link); | 112 | + anyMissingPaths = true; |
| 96 | } | 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