Simplify optical compiler by always searching for common lambda (ONOS-5765)
Change-Id: I9128f59cc9c0bf10b88341cac289fb606906d98b
diff --git a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 5593233..2609cf4 100644
--- a/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/apps/optical-model/src/main/java/org/onosproject/net/optical/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -24,7 +24,6 @@
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.util.Frequency;
import org.onosproject.net.AnnotationKeys;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.ConnectPoint;
@@ -42,8 +41,8 @@
import org.onosproject.net.intent.OpticalConnectivityIntent;
import org.onosproject.net.intent.OpticalPathIntent;
import org.onosproject.net.optical.OchPort;
-import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.Resource;
+import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.ResourceService;
import org.onosproject.net.resource.Resources;
import org.onosproject.net.topology.AdapterLinkWeigher;
@@ -66,7 +65,6 @@
import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkArgument;
-import static org.onosproject.net.OchSignal.toFlexGrid;
import static org.onosproject.net.optical.device.OpticalDeviceServiceView.opticalView;
/**
@@ -108,10 +106,9 @@
// Check if source and destination are optical OCh ports
ConnectPoint src = intent.getSrc();
ConnectPoint dst = intent.getDst();
- Port srcPort = deviceService.getPort(src.deviceId(), src.port());
- Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
- checkArgument(srcPort instanceof OchPort);
- checkArgument(dstPort instanceof OchPort);
+ checkArgument(deviceService.getPort(src.deviceId(), src.port()) instanceof OchPort);
+ checkArgument(deviceService.getPort(dst.deviceId(), dst.port()) instanceof OchPort);
+ List<Resource> resources = new LinkedList<>();
log.debug("Compiling optical connectivity intent between {} and {}", src, dst);
@@ -121,101 +118,30 @@
resourceService.release(intent.key());
// Check OCh port availability
+ // If ports are not available, compilation fails
+ // Else add port to resource reservation list
Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource();
Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource();
- // If ports are not available, compilation fails
if (!Stream.of(srcPortResource, dstPortResource).allMatch(resourceService::isAvailable)) {
log.error("Ports for the intent are not available. Intent: {}", intent);
throw new OpticalIntentCompilationException("Ports for the intent are not available. Intent: " + intent);
}
-
- List<Resource> resources = new ArrayList<>();
resources.add(srcPortResource);
resources.add(dstPortResource);
- // Calculate available light paths
+ // Find first path that has the required resources
Stream<Path> paths = getOpticalPaths(intent);
-
- // Static or dynamic lambda allocation
- String staticLambda = srcPort.annotations().value(AnnotationKeys.STATIC_LAMBDA);
- OchPort srcOchPort = (OchPort) srcPort;
- OchPort dstOchPort = (OchPort) dstPort;
-
- // FIXME: need to actually reserve the lambda for static lambda's
- // static lambda case: early return
- if (staticLambda != null) {
-
- OchSignal lambda = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)),
- srcOchPort.lambda().channelSpacing(),
- srcOchPort.lambda().slotGranularity());
- log.debug("Using statically assigned lambda : {}", lambda);
-
- List<Resource> res = new ArrayList<>();
-
- Path satPath = paths.filter(path -> {
- // FIXME trimming both ends (staticLambda assigned ports)
- // Proper fix is to let device advertise static lambda as resource.
- LinkedList<Link> links = new LinkedList<>(path.links());
- links.pollFirst();
- links.pollLast();
-
- List<Resource> r = convertToResources(links, toFlexGrid(lambda));
- if (r.stream().allMatch(resourceService::isAvailable)) {
- // FIXME bad practice to have side-effect during stream
- res.addAll(r);
- return true;
- }
- return false;
- }).findFirst().orElse(null);
-
- if (satPath == null) {
- // FIXME doing something very wrong to preserve old behavior
- // as a fallback
- log.warn("No feasible path between {}-{} using {}",
- src, dst, lambda);
-
- satPath = getOpticalPaths(intent).iterator().next();
- if (satPath == null) {
- throw new OpticalIntentCompilationException(
- "Unable to find suitable lightpath for intent " + intent);
- }
- return ImmutableList.of(createIntent(intent, satPath, lambda));
- }
-
- resources.addAll(res);
- allocateResources(intent, resources);
-
- return ImmutableList.of(createIntent(intent, satPath, lambda));
- }
-
- // FIXME: also check destination OCh port
- // non-tunable case: early return
- if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) {
- Path firstPath = paths.findAny().orElse(null);
- if (firstPath == null) {
- log.error("Unable to find suitable lightpath for intent {}", intent);
- throw new OpticalIntentCompilationException("Unable to find suitable lightpath for intent " + intent);
- }
- OchSignal lambda = srcOchPort.lambda();
- // TODO apply the same as static lambda case above
- // - pick feasible path
- // - allocate resources
- //resources.addAll(convertToResources(firstPath.links(), toFlexGrid(lambda)));
- allocateResources(intent, resources);
- return ImmutableList.of(createIntent(intent, firstPath, lambda));
- }
-
- // remaining cases
- // Use first path that the required resources are available
Optional<Map.Entry<Path, List<OchSignal>>> found = paths
- .map(path -> Maps.immutableEntry(path, findFirstAvailableOch(path)))
+ .map(path ->
+ Maps.immutableEntry(path, findFirstAvailableLambda(path)))
.filter(entry -> !entry.getValue().isEmpty())
- .filter(entry -> convertToResources(entry.getKey().links(),
+ .filter(entry -> convertToResources(entry.getKey(),
entry.getValue()).stream().allMatch(resourceService::isAvailable))
.findFirst();
+ // Allocate resources and create optical path intent
if (found.isPresent()) {
- resources.addAll(convertToResources(found.get().getKey().links(), found.get().getValue()));
+ resources.addAll(convertToResources(found.get().getKey(), found.get().getValue()));
allocateResources(intent, resources);
@@ -227,9 +153,16 @@
}
}
+ /**
+ * Create installable optical path intent.
+ * Only supports fixed grid for now.
+ *
+ * @param parentIntent this intent (used for resource tracking)
+ * @param path the path to use
+ * @param lambda the lambda to use
+ * @return optical path intent
+ */
private Intent createIntent(OpticalConnectivityIntent parentIntent, Path path, OchSignal lambda) {
- // Create installable optical path intent
- // Only support fixed grid for now
OchSignalType signalType = OchSignalType.FIXED_GRID;
return OpticalPathIntent.builder()
@@ -245,8 +178,30 @@
.build();
}
+ /**
+ * Convert given lambda as discrete resource of all path ports.
+ *
+ * @param path the path
+ * @param lambda the lambda
+ * @return list of discrete resources
+ */
+ private List<Resource> convertToResources(Path path, Collection<OchSignal> lambda) {
+ return path.links().stream()
+ .flatMap(x -> Stream.of(
+ Resources.discrete(x.src().deviceId(), x.src().port()).resource(),
+ Resources.discrete(x.dst().deviceId(), x.dst().port()).resource()
+ ))
+ .flatMap(x -> lambda.stream().map(x::child))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Reserve all required resources for this intent.
+ *
+ * @param intent the intent
+ * @param resources list of resources to reserve
+ */
private void allocateResources(Intent intent, List<Resource> resources) {
- // reserve all of required resources
List<ResourceAllocation> allocations = resourceService.allocate(intent.key(), resources);
if (allocations.isEmpty()) {
log.error("Resource allocation for {} failed (resource request: {})", intent.key(), resources);
@@ -259,8 +214,14 @@
}
}
- private List<OchSignal> findFirstAvailableOch(Path path) {
- Set<OchSignal> lambdas = findCommonLambdasOverLinks(path.links());
+ /**
+ * Find the first available lambda on the given path by checking all the port resources.
+ *
+ * @param path the path
+ * @return list of consecutive and available OChSignals
+ */
+ private List<OchSignal> findFirstAvailableLambda(Path path) {
+ Set<OchSignal> lambdas = findCommonLambdas(path);
if (lambdas.isEmpty()) {
return Collections.emptyList();
}
@@ -268,16 +229,6 @@
return findFirstLambda(lambdas, slotCount());
}
- private List<Resource> convertToResources(List<Link> links, Collection<OchSignal> lambda) {
- return links.stream()
- .flatMap(x -> Stream.of(
- Resources.discrete(x.src().deviceId(), x.src().port()).resource(),
- Resources.discrete(x.dst().deviceId(), x.dst().port()).resource()
- ))
- .flatMap(x -> lambda.stream().map(x::child))
- .collect(Collectors.toList());
- }
-
/**
* Get the number of 12.5 GHz slots required for the path.
*
@@ -290,8 +241,14 @@
return SLOT_COUNT;
}
- private Set<OchSignal> findCommonLambdasOverLinks(List<Link> links) {
- return links.stream()
+ /**
+ * Find common lambdas on all ports that compose the path.
+ *
+ * @param path the path
+ * @return set of common lambdas
+ */
+ private Set<OchSignal> findCommonLambdas(Path path) {
+ return path.links().stream()
.flatMap(x -> Stream.of(
Resources.discrete(x.src().deviceId(), x.src().port()).id(),
Resources.discrete(x.dst().deviceId(), x.dst().port()).id()