Rewrote optical connectivity intent compiler
Change-Id: I5acece3c14bed8a23f7bbe0c5a9bc0932a2a0881
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
index 372d65b..91c9df3 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalConnectivityIntentCompiler.java
@@ -15,6 +15,7 @@
*/
package org.onosproject.net.intent.impl.compiler;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -23,16 +24,31 @@
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.ChannelSpacing;
import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.GridType;
import org.onosproject.net.Link;
+import org.onosproject.net.OchPort;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.OmsPort;
import org.onosproject.net.Path;
+import org.onosproject.net.Port;
+import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.OpticalConnectivityIntent;
import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.impl.PathNotFoundException;
+import org.onosproject.net.resource.DefaultLinkResourceRequest;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.LambdaResource;
+import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LinkResourceAllocations;
+import org.onosproject.net.resource.LinkResourceRequest;
+import org.onosproject.net.resource.LinkResourceService;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceType;
import org.onosproject.net.topology.LinkWeight;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyEdge;
@@ -40,18 +56,32 @@
import com.google.common.collect.ImmutableList;
+import static com.google.common.base.Preconditions.checkArgument;
+
/**
* An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
*/
@Component(immediate = true)
public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
+ private static final GridType DEFAULT_OCH_GRIDTYPE = GridType.DWDM;
+ private static final ChannelSpacing DEFAULT_CHANNEL_SPACING = ChannelSpacing.CHL_50GHZ;
+
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentExtensionService intentManager;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceService deviceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected LinkResourceService linkResourceService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ protected DeviceResourceService deviceResourceService;
+
@Activate
public void activate() {
intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
@@ -66,19 +96,152 @@
public List<Intent> compile(OpticalConnectivityIntent intent,
List<Intent> installable,
Set<LinkResourceAllocations> resources) {
- // TODO: compute multiple paths using the K-shortest path algorithm
- Path path = calculateOpticalPath(intent.getSrc(), intent.getDst());
- Intent newIntent = OpticalPathIntent.builder()
- .appId(intent.appId())
- .src(intent.getSrc())
- .dst(intent.getDst())
- .path(path)
- .build();
- return ImmutableList.of(newIntent);
+ // 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);
+
+ // Calculate available light paths
+ Set<Path> paths = getOpticalPaths(intent);
+
+ // Use first path that can be successfully reserved
+ for (Path path : paths) {
+ // Request and reserve lambda on path
+ LinkResourceAllocations linkAllocs = assignWavelength(intent, path);
+ if (linkAllocs == null) {
+ continue;
+ }
+
+ OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
+
+ // Try to reserve port resources, roll back if unsuccessful
+ Set<Port> portAllocs = deviceResourceService.requestPorts(intent);
+ if (portAllocs == null) {
+ linkResourceService.releaseResources(linkAllocs);
+ continue;
+ }
+
+ // Create installable optical path intent
+ LambdaResourceAllocation lambdaAlloc = getWavelength(path, linkAllocs);
+ OchSignal ochSignal = getOchSignal(lambdaAlloc, omsPort.minFrequency(), omsPort.grid());
+
+ Intent newIntent = OpticalPathIntent.builder()
+ .appId(intent.appId())
+ .src(intent.getSrc())
+ .dst(intent.getDst())
+ .path(path)
+ .lambda(ochSignal)
+ .build();
+
+ return ImmutableList.of(newIntent);
+ }
+
+ return Collections.emptyList();
}
- private Path calculateOpticalPath(ConnectPoint start, ConnectPoint end) {
- // TODO: support user policies
+ /**
+ * Find the lambda allocated to the path.
+ *
+ * @param path the path
+ * @param linkAllocs the link allocations
+ * @return
+ */
+ private LambdaResourceAllocation getWavelength(Path path, LinkResourceAllocations linkAllocs) {
+ for (Link link : path.links()) {
+ for (ResourceAllocation alloc : linkAllocs.getResourceAllocation(link)) {
+ if (alloc.type() == ResourceType.LAMBDA) {
+ return (LambdaResourceAllocation) alloc;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Request and reserve first available wavelength across path.
+ *
+ * @param path path in WDM topology
+ * @return first available lambda resource allocation
+ */
+ private LinkResourceAllocations assignWavelength(Intent intent, Path path) {
+ LinkResourceRequest.Builder request =
+ DefaultLinkResourceRequest.builder(intent.id(), path.links())
+ .addLambdaRequest();
+
+ LinkResourceAllocations allocations = linkResourceService.requestResources(request.build());
+
+ checkWavelengthContinuity(allocations, path);
+
+ return allocations;
+ }
+
+ /**
+ * Checks wavelength continuity constraint across path, i.e., an identical lambda is used on all links.
+ * @return true if wavelength continuity is met, false otherwise
+ */
+ private boolean checkWavelengthContinuity(LinkResourceAllocations allocations, Path path) {
+ if (allocations == null) {
+ return false;
+ }
+
+ LambdaResource lambda = null;
+
+ for (Link link : path.links()) {
+ for (ResourceAllocation alloc : allocations.getResourceAllocation(link)) {
+ if (alloc.type() == ResourceType.LAMBDA) {
+ LambdaResource nextLambda = ((LambdaResourceAllocation) alloc).lambda();
+ if (nextLambda == null) {
+ return false;
+ }
+ if (lambda == null) {
+ lambda = nextLambda;
+ continue;
+ }
+ if (!lambda.equals(nextLambda)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Convert lambda resource allocation in OCh signal.
+ *
+ * @param alloc lambda resource allocation
+ * @param minFrequency minimum frequency
+ * @param grid grid spacing frequency
+ * @return OCh signal
+ */
+ private OchSignal getOchSignal(LambdaResourceAllocation alloc, Frequency minFrequency, Frequency grid) {
+ int channel = alloc.lambda().toInt();
+
+ // Calculate center frequency
+ Frequency centerFrequency = minFrequency.add(grid.multiply(channel)).add(grid.floorDivision(2));
+
+ // Build OCh signal object
+ int spacingMultiplier = (int) (centerFrequency.subtract(OchSignal.CENTER_FREQUENCY).asHz() / grid.asHz());
+ int slotGranularity = (int) (grid.asHz() / ChannelSpacing.CHL_12P5GHZ.frequency().asHz());
+ OchSignal ochSignal = new OchSignal(DEFAULT_OCH_GRIDTYPE, DEFAULT_CHANNEL_SPACING,
+ spacingMultiplier, slotGranularity);
+
+ return ochSignal;
+ }
+
+ /**
+ * Calculates optical paths in WDM topology.
+ *
+ * @param intent optical connectivity intent
+ * @return set of paths in WDM topology
+ */
+ private Set<Path> getOpticalPaths(OpticalConnectivityIntent intent) {
+ // Route in WDM topology
Topology topology = topologyService.currentTopology();
LinkWeight weight = new LinkWeight() {
@Override
@@ -86,18 +249,18 @@
if (edge.link().state() == Link.State.INACTIVE) {
return -1;
}
- return edge.link().type() == Link.Type.OPTICAL ? +1 : -1;
+ if (edge.link().type() != Link.Type.OPTICAL) {
+ return -1;
+ }
+ return edge.link().annotations().value("optical.type").equals("WDM") ? +1 : -1;
}
};
+ ConnectPoint start = intent.getSrc();
+ ConnectPoint end = intent.getDst();
Set<Path> paths = topologyService.getPaths(topology, start.deviceId(),
- end.deviceId(), weight);
- if (paths.isEmpty()) {
- throw new PathNotFoundException(start.elementId(), end.elementId());
- }
+ end.deviceId(), weight);
- // TODO: let's be more intelligent about this eventually
- return paths.iterator().next();
+ return paths;
}
-
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
index 2cf4ccb..84368d9 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompiler.java
@@ -30,29 +30,21 @@
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criteria;
+import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.IntentExtensionService;
import org.onosproject.net.intent.OpticalPathIntent;
-import org.onosproject.net.intent.impl.IntentCompilationException;
-import org.onosproject.net.resource.DefaultLinkResourceRequest;
-import org.onosproject.net.resource.LambdaResource;
-import org.onosproject.net.resource.LambdaResourceAllocation;
import org.onosproject.net.resource.LinkResourceAllocations;
-import org.onosproject.net.resource.LinkResourceRequest;
import org.onosproject.net.resource.LinkResourceService;
-import org.onosproject.net.resource.ResourceAllocation;
-import org.onosproject.net.resource.ResourceType;
-import org.onosproject.net.topology.TopologyService;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import static org.onosproject.net.flow.DefaultTrafficTreatment.builder;
-
@Component(immediate = true)
public class OpticalPathIntentCompiler implements IntentCompiler<OpticalPathIntent> {
@@ -63,15 +55,10 @@
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected TopologyService topologyService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LinkResourceService resourceService;
private ApplicationId appId;
- static final short SIGNAL_TYPE = (short) 1;
-
@Activate
public void activate() {
appId = coreService.registerApplication("org.onosproject.net.intent");
@@ -86,64 +73,50 @@
@Override
public List<Intent> compile(OpticalPathIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
- LinkResourceAllocations allocations = assignWavelength(intent);
-
return Collections.singletonList(
- new FlowRuleIntent(appId, createRules(intent, allocations), intent.resources()));
+ new FlowRuleIntent(appId, createRules(intent), intent.resources()));
}
- private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
- LinkResourceRequest.Builder request = DefaultLinkResourceRequest
- .builder(intent.id(), intent.path().links())
- .addLambdaRequest();
- return resourceService.requestResources(request.build());
- }
-
- private List<FlowRule> createRules(OpticalPathIntent intent, LinkResourceAllocations allocations) {
+ private List<FlowRule> createRules(OpticalPathIntent intent) {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInPort(intent.src().port());
List<FlowRule> rules = new LinkedList<>();
- ConnectPoint prev = intent.src();
+ ConnectPoint current = intent.src();
for (Link link : intent.path().links()) {
- ResourceAllocation allocation = allocations.getResourceAllocation(link).stream()
- .filter(x -> x.type() == ResourceType.LAMBDA)
- .findFirst()
- .orElseThrow(() -> new IntentCompilationException("Lambda was not assigned successfully"));
- LambdaResource la = ((LambdaResourceAllocation) allocation).lambda();
-
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
- treatmentBuilder.setLambda((short) la.toInt());
+ treatmentBuilder.add(Instructions.modL0Lambda(intent.lambda()));
treatmentBuilder.setOutput(link.src().port());
- FlowRule rule = new DefaultFlowRule(prev.deviceId(),
- selectorBuilder.build(),
- treatmentBuilder.build(),
- 100,
- appId,
- 100,
- true);
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(current.deviceId())
+ .withSelector(selectorBuilder.build())
+ .withTreatment(treatmentBuilder.build())
+ .withPriority(100)
+ .fromApp(appId)
+ .makePermanent()
+ .build();
rules.add(rule);
- prev = link.dst();
+ current = link.dst();
selectorBuilder.matchInPort(link.dst().port());
- selectorBuilder.matchOpticalSignalType(SIGNAL_TYPE);
- selectorBuilder.matchLambda((short) la.toInt());
-
+ selectorBuilder.add(Criteria.matchLambda(intent.lambda()));
}
- // build the last T port rule
- TrafficTreatment.Builder treatmentLast = builder();
+ // Build the egress ROADM rule
+ TrafficTreatment.Builder treatmentLast = DefaultTrafficTreatment.builder();
treatmentLast.setOutput(intent.dst().port());
- FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
- selectorBuilder.build(),
- treatmentLast.build(),
- 100,
- appId,
- 100,
- true);
+
+ FlowRule rule = new DefaultFlowRule.Builder()
+ .forDevice(intent.dst().deviceId())
+ .withSelector(selectorBuilder.build())
+ .withTreatment(treatmentLast.build())
+ .withPriority(100)
+ .fromApp(appId)
+ .makePermanent()
+ .build();
rules.add(rule);
return rules;
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java
new file mode 100644
index 0000000..cfa290b
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/DeviceResourceManager.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.resource.impl;
+
+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.apache.felix.scr.annotations.Service;
+import org.onosproject.net.Port;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.intent.OpticalConnectivityIntent;
+import org.onosproject.net.resource.DeviceResourceService;
+import org.onosproject.net.resource.DeviceResourceStore;
+import org.slf4j.Logger;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides basic implementation of device resources allocation.
+ */
+@Component(immediate = true)
+@Service
+public class DeviceResourceManager implements DeviceResourceService {
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ private DeviceResourceStore store;
+
+ @Activate
+ public void activate() {
+ log.info("Started");
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Stopped");
+ }
+
+ @Override
+ public Set<Port> requestPorts(Intent intent) {
+ checkNotNull(intent);
+ if (intent instanceof OpticalConnectivityIntent) {
+ OpticalConnectivityIntent opticalIntent = (OpticalConnectivityIntent) intent;
+ Set<Port> srcPorts = store.getFreePorts(opticalIntent.getSrc().deviceId());
+ Set<Port> dstPorts = store.getFreePorts(opticalIntent.getDst().deviceId());
+
+ Port srcPort = getTypedPort(srcPorts, Port.Type.OCH);
+ Port dstPort = getTypedPort(dstPorts, Port.Type.OCH);
+
+ if (srcPort == null || dstPort == null) {
+ return null;
+ }
+
+ Set<Port> allocPorts = new HashSet(Arrays.asList(srcPort, dstPort));
+
+ store.allocatePorts(allocPorts, intent.id());
+
+ return allocPorts;
+ }
+
+ return null;
+ }
+
+ @Override
+ public void releasePorts(IntentId intentId) {
+ store.releasePorts(intentId);
+ }
+
+ private Port getTypedPort(Set<Port> ports, Port.Type type) {
+ for (Port port : ports) {
+ if (port.type() == type) {
+ return port;
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
index 08e8e4f..a18f2c5 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/OpticalPathIntentCompilerTest.java
@@ -52,6 +52,7 @@
import static org.onosproject.net.Link.Type.DIRECT;
import static org.onosproject.net.NetTestTools.PID;
import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.NetTestTools.createLambda;
public class OpticalPathIntentCompilerTest {
@@ -93,6 +94,7 @@
.src(d1p1)
.dst(d3p1)
.path(new DefaultPath(PID, links, hops))
+ .lambda(createLambda())
.build();
intentExtensionService = createMock(IntentExtensionService.class);
intentExtensionService.registerCompiler(OpticalPathIntent.class, sut);