ONOS-5799: Make SP2MP compiler partial failure constraint aware

Change-Id: I741c3a22916e7e51e5882bd3993d425e78f18bda
This commit is contained in:
Luca Prete 2017-01-03 15:59:30 -08:00 committed by Jonathan Hart
parent 61bb7f4d6a
commit d26ea65e84
7 changed files with 76 additions and 55 deletions

View File

@ -94,6 +94,25 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
* @return Path between the two * @return Path between the two
* @throws PathNotFoundException if a path cannot be found * @throws PathNotFoundException if a path cannot be found
*/ */
@Deprecated
protected Path getPathOrException(ConnectivityIntent intent,
ElementId one, ElementId two) {
Path path = getPath(intent, one, two);
if (path == null) {
throw new PathNotFoundException(one, two);
}
// TODO: let's be more intelligent about this eventually
return path;
}
/**
* Computes a path between two ConnectPoints.
*
* @param intent intent on which behalf path is being computed
* @param one start of the path
* @param two end of the path
* @return Path between the two, or null if no path can be found
*/
protected Path getPath(ConnectivityIntent intent, protected Path getPath(ConnectivityIntent intent,
ElementId one, ElementId two) { ElementId one, ElementId two) {
Set<Path> paths = pathService.getPaths(one, two, weight(intent.constraints())); Set<Path> paths = pathService.getPaths(one, two, weight(intent.constraints()));
@ -102,7 +121,7 @@ public abstract class ConnectivityIntentCompiler<T extends ConnectivityIntent>
.filter(path -> checkPath(path, constraints)) .filter(path -> checkPath(path, constraints))
.toList(); .toList();
if (filtered.isEmpty()) { if (filtered.isEmpty()) {
throw new PathNotFoundException(one, two); return null;
} }
// TODO: let's be more intelligent about this eventually // TODO: let's be more intelligent about this eventually
return filtered.iterator().next(); return filtered.iterator().next();

View File

@ -82,9 +82,9 @@ public class HostToHostIntentCompiler
} }
boolean isAsymmetric = intent.constraints().contains(new AsymmetricPathConstraint()); boolean isAsymmetric = intent.constraints().contains(new AsymmetricPathConstraint());
Path pathOne = getPath(intent, intent.one(), intent.two()); Path pathOne = getPathOrException(intent, intent.one(), intent.two());
Path pathTwo = isAsymmetric ? Path pathTwo = isAsymmetric ?
getPath(intent, intent.two(), intent.one()) : invertPath(pathOne); getPathOrException(intent, intent.two(), intent.one()) : invertPath(pathOne);
Host one = hostService.getHost(intent.one()); Host one = hostService.getHost(intent.one());
Host two = hostService.getHost(intent.two()); Host two = hostService.getHost(intent.two());

View File

@ -70,8 +70,8 @@ public class MplsIntentCompiler extends ConnectivityIntentCompiler<MplsIntent>
} }
List<Link> links = new ArrayList<>(); List<Link> links = new ArrayList<>();
Path path = getPath(intent, ingressPoint.deviceId(), Path path = getPathOrException(intent, ingressPoint.deviceId(),
egressPoint.deviceId()); egressPoint.deviceId());
links.add(createEdgeLink(ingressPoint, true)); links.add(createEdgeLink(ingressPoint, true));
links.addAll(path.links()); links.addAll(path.links());

View File

@ -28,19 +28,16 @@ import org.onosproject.net.Link;
import org.onosproject.net.Path; import org.onosproject.net.Path;
import org.onosproject.net.device.DeviceService; import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentException; import org.onosproject.net.intent.IntentException;
import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.LinkCollectionIntent; import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.MultiPointToSinglePointIntent; import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.PointToPointIntent; import org.onosproject.net.intent.PointToPointIntent;
import org.onosproject.net.topology.PathService;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure; import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
@ -51,14 +48,11 @@ import static org.onosproject.net.intent.constraint.PartialFailureConstraint.int
*/ */
@Component(immediate = true) @Component(immediate = true)
public class MultiPointToSinglePointIntentCompiler public class MultiPointToSinglePointIntentCompiler
implements IntentCompiler<MultiPointToSinglePointIntent> { extends ConnectivityIntentCompiler<MultiPointToSinglePointIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager; protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PathService pathService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService; protected DeviceService deviceService;
@ -78,22 +72,23 @@ public class MultiPointToSinglePointIntentCompiler
ConnectPoint egressPoint = intent.egressPoint(); ConnectPoint egressPoint = intent.egressPoint();
final boolean allowMissingPaths = intentAllowsPartialFailure(intent); final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
boolean partialTree = false; boolean hasPaths = false;
boolean anyMissingPaths = false; boolean missingSomePaths = false;
for (ConnectPoint ingressPoint : intent.ingressPoints()) { for (ConnectPoint ingressPoint : intent.ingressPoints()) {
if (ingressPoint.deviceId().equals(egressPoint.deviceId())) { if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
if (deviceService.isAvailable(ingressPoint.deviceId())) { if (deviceService.isAvailable(ingressPoint.deviceId())) {
partialTree = true; hasPaths = true;
} else { } else {
anyMissingPaths = true; missingSomePaths = true;
} }
continue; continue;
} }
Path path = getPath(ingressPoint, intent.egressPoint()); Path path = getPath(intent, ingressPoint.deviceId(), intent.egressPoint().deviceId());
if (path != null) { if (path != null) {
partialTree = true; hasPaths = true;
for (Link link : path.links()) { for (Link link : path.links()) {
if (links.containsKey(link.dst().deviceId())) { if (links.containsKey(link.dst().deviceId())) {
@ -107,14 +102,14 @@ public class MultiPointToSinglePointIntentCompiler
links.put(link.src().deviceId(), link); links.put(link.src().deviceId(), link);
} }
} else { } else {
anyMissingPaths = true; missingSomePaths = true;
} }
} }
if (!partialTree) { if (!hasPaths) {
throw new IntentException("Could not find any paths between ingress and egress points."); throw new IntentException("Cannot find any path between ingress and egress points.");
} else if (!allowMissingPaths && anyMissingPaths) { } else if (!allowMissingPaths && missingSomePaths) {
throw new IntentException("Missing some paths between ingress and egress ports."); throw new IntentException("Missing some paths between ingress and egress points.");
} }
Intent result = LinkCollectionIntent.builder() Intent result = LinkCollectionIntent.builder()
@ -131,20 +126,4 @@ public class MultiPointToSinglePointIntentCompiler
return Collections.singletonList(result); return Collections.singletonList(result);
} }
/**
* Computes a path between two ConnectPoints.
*
* @param one start of the path
* @param two end of the path
* @return Path between the two
*/
private Path getPath(ConnectPoint one, ConnectPoint two) {
Set<Path> paths = pathService.getPaths(one.deviceId(), two.deviceId());
if (paths.isEmpty()) {
return null;
}
// TODO: let's be more intelligent about this eventually
return paths.iterator().next();
}
} }

View File

@ -161,8 +161,8 @@ public class PointToPointIntentCompiler
ConnectPoint egressPoint, ConnectPoint egressPoint,
PointToPointIntent intent) { PointToPointIntent intent) {
List<Link> links = new ArrayList<>(); List<Link> links = new ArrayList<>();
Path path = getPath(intent, ingressPoint.deviceId(), Path path = getPathOrException(intent, ingressPoint.deviceId(),
egressPoint.deviceId()); egressPoint.deviceId());
links.add(createEdgeLink(ingressPoint, true)); links.add(createEdgeLink(ingressPoint, true));
links.addAll(path.links()); links.addAll(path.links());
@ -174,8 +174,8 @@ public class PointToPointIntentCompiler
} }
private List<Intent> createUnprotectedLinkCollectionIntent(PointToPointIntent intent) { private List<Intent> createUnprotectedLinkCollectionIntent(PointToPointIntent intent) {
Path path = getPath(intent, intent.filteredIngressPoint().connectPoint().deviceId(), Path path = getPathOrException(intent, intent.filteredIngressPoint().connectPoint().deviceId(),
intent.filteredEgressPoint().connectPoint().deviceId()); intent.filteredEgressPoint().connectPoint().deviceId());
return asList(createLinkCollectionIntent(ImmutableSet.copyOf(path.links()), return asList(createLinkCollectionIntent(ImmutableSet.copyOf(path.links()),
path.cost(), path.cost(),
@ -274,8 +274,8 @@ public class PointToPointIntentCompiler
PointToPointIntent intent, PointToPointIntent intent,
List<Intent> installable) { List<Intent> installable) {
List<Link> links = new ArrayList<>(); List<Link> links = new ArrayList<>();
Path onlyPath = getPath(intent, ingressPoint.deviceId(), Path onlyPath = getPathOrException(intent, ingressPoint.deviceId(),
egressPoint.deviceId()); egressPoint.deviceId());
List<Intent> reusableIntents = null; List<Intent> reusableIntents = null;
if (installable != null) { if (installable != null) {

View File

@ -19,31 +19,34 @@ import com.google.common.collect.ImmutableSet;
import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onosproject.net.ConnectPoint; import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Link; import org.onosproject.net.Link;
import org.onosproject.net.Path; import org.onosproject.net.Path;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentException;
import org.onosproject.net.intent.LinkCollectionIntent; import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.SinglePointToMultiPointIntent; import org.onosproject.net.intent.SinglePointToMultiPointIntent;
import org.onosproject.net.provider.ProviderId;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
@Component(immediate = true) @Component(immediate = true)
public class SinglePointToMultiPointIntentCompiler public class SinglePointToMultiPointIntentCompiler
extends ConnectivityIntentCompiler<SinglePointToMultiPointIntent> { extends ConnectivityIntentCompiler<SinglePointToMultiPointIntent> {
// TODO: use off-the-shell core provider ID @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
private static final ProviderId PID = protected DeviceService deviceService;
new ProviderId("core", "org.onosproject.core", true);
@Activate @Activate
public void activate() { public void activate() {
intentManager.registerCompiler(SinglePointToMultiPointIntent.class, intentManager.registerCompiler(SinglePointToMultiPointIntent.class, this);
this);
} }
@Deactivate @Deactivate
@ -51,19 +54,40 @@ public class SinglePointToMultiPointIntentCompiler
intentManager.unregisterCompiler(SinglePointToMultiPointIntent.class); intentManager.unregisterCompiler(SinglePointToMultiPointIntent.class);
} }
@Override @Override
public List<Intent> compile(SinglePointToMultiPointIntent intent, public List<Intent> compile(SinglePointToMultiPointIntent intent,
List<Intent> installable) { List<Intent> installable) {
Set<Link> links = new HashSet<>(); Set<Link> links = new HashSet<>();
final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
boolean hasPaths = false;
boolean missingSomePaths = false;
for (ConnectPoint egressPoint : intent.egressPoints()) { for (ConnectPoint egressPoint : intent.egressPoints()) {
if (egressPoint.deviceId().equals(intent.ingressPoint().deviceId())) { if (egressPoint.deviceId().equals(intent.ingressPoint().deviceId())) {
// Do not need to look for paths, since ingress and egress
// devices are the same.
if (deviceService.isAvailable(egressPoint.deviceId())) {
hasPaths = true;
} else {
missingSomePaths = true;
}
continue; continue;
} }
Path path = getPath(intent, intent.ingressPoint().deviceId(), egressPoint.deviceId()); Path path = getPath(intent, intent.ingressPoint().deviceId(), egressPoint.deviceId());
links.addAll(path.links()); if (path != null) {
hasPaths = true;
links.addAll(path.links());
} else {
missingSomePaths = true;
}
}
if (!hasPaths) {
throw new IntentException("Cannot find any path between ingress and egress points.");
} else if (!allowMissingPaths && missingSomePaths) {
throw new IntentException("Missing some paths between ingress and egress points.");
} }
Intent result = LinkCollectionIntent.builder() Intent result = LinkCollectionIntent.builder()

View File

@ -293,7 +293,6 @@ public class MultiPointToSinglePointIntentCompilerTest extends AbstractIntentTes
*/ */
@Test @Test
public void testNonTrivialSelectorsIntent() { public void testNonTrivialSelectorsIntent() {
Set<FilteredConnectPoint> ingress = ImmutableSet.of( Set<FilteredConnectPoint> ingress = ImmutableSet.of(
new FilteredConnectPoint(connectPoint("of1", 1), new FilteredConnectPoint(connectPoint("of1", 1),
DefaultTrafficSelector.builder().matchVlanId(VlanId.vlanId("100")).build()), DefaultTrafficSelector.builder().matchVlanId(VlanId.vlanId("100")).build()),