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
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
index 5c158e0..8fad769 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/MultiPointToSinglePointIntentCompiler.java
@@ -26,13 +26,14 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.Path;
+import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.IntentException;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.PointToPointIntent;
-import org.onosproject.net.intent.impl.PathNotFoundException;
import org.onosproject.net.resource.link.LinkResourceAllocations;
import org.onosproject.net.topology.PathService;
@@ -42,6 +43,9 @@
import java.util.Map;
import java.util.Set;
+import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
+
+
/**
* An intent compiler for
* {@link org.onosproject.net.intent.MultiPointToSinglePointIntent}.
@@ -56,6 +60,9 @@
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PathService pathService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
@Activate
public void activate() {
intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this);
@@ -72,23 +79,44 @@
Map<DeviceId, Link> links = new HashMap<>();
ConnectPoint egressPoint = intent.egressPoint();
+ final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
+ boolean partialTree = false;
+ boolean anyMissingPaths = false;
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
- continue;
- }
- Path path = getPath(ingressPoint, intent.egressPoint());
- for (Link link : path.links()) {
- if (links.containsKey(link.src().deviceId())) {
- // We've already reached the existing tree with the first
- // part of this path. Add the merging point with different
- // incoming port, but don't add the remainder of the path
- // in case it differs from the path we already have.
- links.put(link.src().deviceId(), link);
- break;
+ if (deviceService.isAvailable(ingressPoint.deviceId())) {
+ partialTree = true;
+ } else {
+ anyMissingPaths = true;
}
- links.put(link.src().deviceId(), link);
+ continue;
}
+
+ Path path = getPath(ingressPoint, intent.egressPoint());
+ if (path != null) {
+ partialTree = true;
+
+ for (Link link : path.links()) {
+ if (links.containsKey(link.src().deviceId())) {
+ // We've already reached the existing tree with the first
+ // part of this path. Add the merging point with different
+ // incoming port, but don't add the remainder of the path
+ // in case it differs from the path we already have.
+ links.put(link.src().deviceId(), link);
+ break;
+ }
+ links.put(link.src().deviceId(), link);
+ }
+ } else {
+ anyMissingPaths = true;
+ }
+ }
+
+ if (!partialTree) {
+ throw new IntentException("Could not find any paths between ingress and egress points.");
+ } else if (!allowMissingPaths && anyMissingPaths) {
+ throw new IntentException("Missing some paths between ingress and egress ports.");
}
Intent result = LinkCollectionIntent.builder()
@@ -111,12 +139,11 @@
* @param one start of the path
* @param two end of the path
* @return Path between the two
- * @throws org.onosproject.net.intent.impl.PathNotFoundException if a path cannot be found
*/
private Path getPath(ConnectPoint one, ConnectPoint two) {
Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId());
if (paths.isEmpty()) {
- throw new PathNotFoundException(one.elementId(), two.elementId());
+ return null;
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();