2 * Copyright 2014-2015 Open Networking Laboratory
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.onosproject.net.intent.impl.compiler;
18 import com.google.common.collect.ImmutableList;
19 import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.Iterables;
21 import com.google.common.collect.Sets;
22 import org.apache.felix.scr.annotations.Activate;
23 import org.apache.felix.scr.annotations.Component;
24 import org.apache.felix.scr.annotations.Deactivate;
25 import org.apache.felix.scr.annotations.Reference;
26 import org.apache.felix.scr.annotations.ReferenceCardinality;
27 import org.onlab.util.Frequency;
28 import org.onosproject.net.AnnotationKeys;
29 import org.onosproject.net.ConnectPoint;
30 import org.onosproject.net.DeviceId;
31 import org.onosproject.net.IndexedLambda;
32 import org.onosproject.net.Link;
33 import org.onosproject.net.OchPort;
34 import org.onosproject.net.OchSignal;
35 import org.onosproject.net.OchSignalType;
36 import org.onosproject.net.OmsPort;
37 import org.onosproject.net.Path;
38 import org.onosproject.net.Port;
39 import org.onosproject.net.device.DeviceService;
40 import org.onosproject.net.intent.Intent;
41 import org.onosproject.net.intent.IntentCompiler;
42 import org.onosproject.net.intent.IntentExtensionService;
43 import org.onosproject.net.intent.OpticalConnectivityIntent;
44 import org.onosproject.net.intent.OpticalPathIntent;
45 import org.onosproject.net.intent.impl.IntentCompilationException;
46 import org.onosproject.net.newresource.ResourceAllocation;
47 import org.onosproject.net.newresource.ResourcePath;
48 import org.onosproject.net.newresource.ResourceService;
49 import org.onosproject.net.resource.link.LinkResourceAllocations;
50 import org.onosproject.net.topology.LinkWeight;
51 import org.onosproject.net.topology.Topology;
52 import org.onosproject.net.topology.TopologyService;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
56 import java.util.Collections;
57 import java.util.List;
59 import java.util.stream.Collectors;
61 import static com.google.common.base.Preconditions.checkArgument;
62 import static org.onosproject.net.LinkKey.linkKey;
65 * An intent compiler for {@link org.onosproject.net.intent.OpticalConnectivityIntent}.
67 // For now, remove component designation until dependency on the new resource manager is available.
68 @Component(immediate = true)
69 public class OpticalConnectivityIntentCompiler implements IntentCompiler<OpticalConnectivityIntent> {
71 protected static final Logger log = LoggerFactory.getLogger(OpticalConnectivityIntentCompiler.class);
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected IntentExtensionService intentManager;
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected TopologyService topologyService;
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected DeviceService deviceService;
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected ResourceService resourceService;
86 public void activate() {
87 intentManager.registerCompiler(OpticalConnectivityIntent.class, this);
91 public void deactivate() {
92 intentManager.unregisterCompiler(OpticalConnectivityIntent.class);
96 public List<Intent> compile(OpticalConnectivityIntent intent,
97 List<Intent> installable,
98 Set<LinkResourceAllocations> resources) {
99 // Check if source and destination are optical OCh ports
100 ConnectPoint src = intent.getSrc();
101 ConnectPoint dst = intent.getDst();
102 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
103 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
104 checkArgument(srcPort instanceof OchPort);
105 checkArgument(dstPort instanceof OchPort);
107 log.debug("Compiling optical connectivity intent between {} and {}", src, dst);
110 ResourcePath srcPortPath = ResourcePath.discrete(src.deviceId(), src.port());
111 ResourcePath dstPortPath = ResourcePath.discrete(dst.deviceId(), dst.port());
112 List<org.onosproject.net.newresource.ResourceAllocation> allocation =
113 resourceService.allocate(intent.id(), srcPortPath, dstPortPath);
114 if (allocation.isEmpty()) {
115 throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
118 // Calculate available light paths
119 Set<Path> paths = getOpticalPaths(intent);
121 // Use first path that can be successfully reserved
122 for (Path path : paths) {
124 // Static or dynamic lambda allocation
125 String staticLambda = srcPort.annotations().value(AnnotationKeys.STATIC_LAMBDA);
126 OchPort srcOchPort = (OchPort) srcPort;
127 OchPort dstOchPort = (OchPort) dstPort;
130 // FIXME: need to actually reserve the lambda for static lambda's
131 if (staticLambda != null) {
132 ochSignal = new OchSignal(Frequency.ofHz(Long.parseLong(staticLambda)),
133 srcOchPort.lambda().channelSpacing(),
134 srcOchPort.lambda().slotGranularity());
135 } else if (!srcOchPort.isTunable() || !dstOchPort.isTunable()) {
136 // FIXME: also check OCh port
137 ochSignal = srcOchPort.lambda();
139 // Request and reserve lambda on path
140 IndexedLambda lambda = assignWavelength(intent, path);
141 if (lambda == null) {
144 OmsPort omsPort = (OmsPort) deviceService.getPort(path.src().deviceId(), path.src().port());
145 ochSignal = new OchSignal((int) lambda.index(), omsPort.maxFrequency(), omsPort.grid());
148 // Create installable optical path intent
149 // Only support fixed grid for now
150 OchSignalType signalType = OchSignalType.FIXED_GRID;
152 Intent newIntent = OpticalPathIntent.builder()
153 .appId(intent.appId())
154 .src(intent.getSrc())
155 .dst(intent.getDst())
158 .signalType(signalType)
159 .bidirectional(intent.isBidirectional())
162 return ImmutableList.of(newIntent);
165 // Release port allocations if unsuccessful
166 resourceService.release(intent.id());
168 throw new IntentCompilationException("Unable to find suitable lightpath for intent " + intent);
172 * Request and reserve first available wavelength across path.
174 * @param path path in WDM topology
175 * @return first available lambda allocated
177 private IndexedLambda assignWavelength(Intent intent, Path path) {
178 Set<IndexedLambda> lambdas = findCommonLambdasOverLinks(path.links());
179 if (lambdas.isEmpty()) {
183 IndexedLambda minLambda = findFirstLambda(lambdas);
184 List<ResourcePath> lambdaResources = path.links().stream()
185 .map(x -> ResourcePath.discrete(linkKey(x.src(), x.dst())))
186 .map(x -> x.child(minLambda))
187 .collect(Collectors.toList());
189 List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), lambdaResources);
190 if (allocations.isEmpty()) {
191 log.info("Resource allocation for {} failed (resource request: {})", intent, lambdaResources);
198 private Set<IndexedLambda> findCommonLambdasOverLinks(List<Link> links) {
199 return links.stream()
200 .map(x -> ResourcePath.discrete(linkKey(x.src(), x.dst())))
201 .map(resourceService::getAvailableResources)
202 .map(x -> Iterables.filter(x, r -> r.last() instanceof IndexedLambda))
203 .map(x -> Iterables.transform(x, r -> (IndexedLambda) r.last()))
204 .map(x -> (Set<IndexedLambda>) ImmutableSet.copyOf(x))
205 .reduce(Sets::intersection)
206 .orElse(Collections.emptySet());
209 private IndexedLambda findFirstLambda(Set<IndexedLambda> lambdas) {
210 return lambdas.stream()
215 private ConnectPoint staticPort(ConnectPoint connectPoint) {
216 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
218 String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT);
220 // FIXME: need a better way to match the port
221 if (staticPort != null) {
222 for (Port p : deviceService.getPorts(connectPoint.deviceId())) {
223 if (staticPort.equals(p.number().name())) {
224 return new ConnectPoint(p.element().id(), p.number());
233 * Calculates optical paths in WDM topology.
235 * @param intent optical connectivity intent
236 * @return set of paths in WDM topology
238 private Set<Path> getOpticalPaths(OpticalConnectivityIntent intent) {
239 // Route in WDM topology
240 Topology topology = topologyService.currentTopology();
241 LinkWeight weight = edge -> {
242 // Disregard inactive or non-optical links
243 if (edge.link().state() == Link.State.INACTIVE) {
246 if (edge.link().type() != Link.Type.OPTICAL) {
249 // Adhere to static port mappings
250 DeviceId srcDeviceId = edge.link().src().deviceId();
251 if (srcDeviceId.equals(intent.getSrc().deviceId())) {
252 ConnectPoint srcStaticPort = staticPort(intent.getSrc());
253 if (srcStaticPort != null) {
254 return srcStaticPort.equals(edge.link().src()) ? 1 : -1;
257 DeviceId dstDeviceId = edge.link().dst().deviceId();
258 if (dstDeviceId.equals(intent.getDst().deviceId())) {
259 ConnectPoint dstStaticPort = staticPort(intent.getDst());
260 if (dstStaticPort != null) {
261 return dstStaticPort.equals(edge.link().dst()) ? 1 : -1;
268 ConnectPoint start = intent.getSrc();
269 ConnectPoint end = intent.getDst();
270 Set<Path> paths = topologyService.getPaths(topology, start.deviceId(),
271 end.deviceId(), weight);