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
* @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,
ElementId one, ElementId two) {
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))
.toList();
if (filtered.isEmpty()) {
throw new PathNotFoundException(one, two);
return null;
}
// TODO: let's be more intelligent about this eventually
return filtered.iterator().next();

View File

@ -82,9 +82,9 @@ public class HostToHostIntentCompiler
}
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 ?
getPath(intent, intent.two(), intent.one()) : invertPath(pathOne);
getPathOrException(intent, intent.two(), intent.one()) : invertPath(pathOne);
Host one = hostService.getHost(intent.one());
Host two = hostService.getHost(intent.two());

View File

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

View File

@ -28,19 +28,16 @@ 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.topology.PathService;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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)
public class MultiPointToSinglePointIntentCompiler
implements IntentCompiler<MultiPointToSinglePointIntent> {
extends ConnectivityIntentCompiler<MultiPointToSinglePointIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PathService pathService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@ -78,22 +72,23 @@ public class MultiPointToSinglePointIntentCompiler
ConnectPoint egressPoint = intent.egressPoint();
final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
boolean partialTree = false;
boolean anyMissingPaths = false;
boolean hasPaths = false;
boolean missingSomePaths = false;
for (ConnectPoint ingressPoint : intent.ingressPoints()) {
if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
if (deviceService.isAvailable(ingressPoint.deviceId())) {
partialTree = true;
hasPaths = true;
} else {
anyMissingPaths = true;
missingSomePaths = true;
}
continue;
}
Path path = getPath(ingressPoint, intent.egressPoint());
Path path = getPath(intent, ingressPoint.deviceId(), intent.egressPoint().deviceId());
if (path != null) {
partialTree = true;
hasPaths = true;
for (Link link : path.links()) {
if (links.containsKey(link.dst().deviceId())) {
@ -107,14 +102,14 @@ public class MultiPointToSinglePointIntentCompiler
links.put(link.src().deviceId(), link);
}
} else {
anyMissingPaths = true;
missingSomePaths = 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.");
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()
@ -131,20 +126,4 @@ public class MultiPointToSinglePointIntentCompiler
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,
PointToPointIntent intent) {
List<Link> links = new ArrayList<>();
Path path = getPath(intent, ingressPoint.deviceId(),
egressPoint.deviceId());
Path path = getPathOrException(intent, ingressPoint.deviceId(),
egressPoint.deviceId());
links.add(createEdgeLink(ingressPoint, true));
links.addAll(path.links());
@ -174,8 +174,8 @@ public class PointToPointIntentCompiler
}
private List<Intent> createUnprotectedLinkCollectionIntent(PointToPointIntent intent) {
Path path = getPath(intent, intent.filteredIngressPoint().connectPoint().deviceId(),
intent.filteredEgressPoint().connectPoint().deviceId());
Path path = getPathOrException(intent, intent.filteredIngressPoint().connectPoint().deviceId(),
intent.filteredEgressPoint().connectPoint().deviceId());
return asList(createLinkCollectionIntent(ImmutableSet.copyOf(path.links()),
path.cost(),
@ -274,8 +274,8 @@ public class PointToPointIntentCompiler
PointToPointIntent intent,
List<Intent> installable) {
List<Link> links = new ArrayList<>();
Path onlyPath = getPath(intent, ingressPoint.deviceId(),
egressPoint.deviceId());
Path onlyPath = getPathOrException(intent, ingressPoint.deviceId(),
egressPoint.deviceId());
List<Intent> reusableIntents = 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.Component;
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.Link;
import org.onosproject.net.Path;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentException;
import org.onosproject.net.intent.LinkCollectionIntent;
import org.onosproject.net.intent.SinglePointToMultiPointIntent;
import org.onosproject.net.provider.ProviderId;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.onosproject.net.intent.constraint.PartialFailureConstraint.intentAllowsPartialFailure;
@Component(immediate = true)
public class SinglePointToMultiPointIntentCompiler
extends ConnectivityIntentCompiler<SinglePointToMultiPointIntent> {
// TODO: use off-the-shell core provider ID
private static final ProviderId PID =
new ProviderId("core", "org.onosproject.core", true);
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceService deviceService;
@Activate
public void activate() {
intentManager.registerCompiler(SinglePointToMultiPointIntent.class,
this);
intentManager.registerCompiler(SinglePointToMultiPointIntent.class, this);
}
@Deactivate
@ -51,19 +54,40 @@ public class SinglePointToMultiPointIntentCompiler
intentManager.unregisterCompiler(SinglePointToMultiPointIntent.class);
}
@Override
public List<Intent> compile(SinglePointToMultiPointIntent intent,
List<Intent> installable) {
Set<Link> links = new HashSet<>();
final boolean allowMissingPaths = intentAllowsPartialFailure(intent);
boolean hasPaths = false;
boolean missingSomePaths = false;
for (ConnectPoint egressPoint : intent.egressPoints()) {
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;
}
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()

View File

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