2 * Copyright 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 org.apache.commons.lang3.tuple.Pair;
19 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Modified;
22 import org.apache.felix.scr.annotations.Property;
23 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.onlab.util.Tools;
26 import org.onosproject.cfg.ComponentConfigService;
27 import org.onosproject.core.ApplicationId;
28 import org.onosproject.core.CoreService;
29 import org.onosproject.net.AnnotationKeys;
30 import org.onosproject.net.ConnectPoint;
31 import org.onosproject.net.OchPort;
32 import org.onosproject.net.OduCltPort;
33 import org.onosproject.net.OduSignalType;
34 import org.onosproject.net.Port;
35 import org.onosproject.net.device.DeviceService;
36 import org.onosproject.net.flow.DefaultFlowRule;
37 import org.onosproject.net.flow.DefaultTrafficSelector;
38 import org.onosproject.net.flow.DefaultTrafficTreatment;
39 import org.onosproject.net.flow.FlowRule;
40 import org.onosproject.net.flow.TrafficSelector;
41 import org.onosproject.net.flow.TrafficTreatment;
42 import org.onosproject.net.intent.FlowRuleIntent;
43 import org.onosproject.net.intent.Intent;
44 import org.onosproject.net.intent.IntentCompiler;
45 import org.onosproject.net.intent.IntentExtensionService;
46 import org.onosproject.net.intent.IntentId;
47 import org.onosproject.net.intent.IntentService;
48 import org.onosproject.net.intent.OpticalCircuitIntent;
49 import org.onosproject.net.intent.OpticalConnectivityIntent;
50 import org.onosproject.net.intent.impl.IntentCompilationException;
51 import org.onosproject.net.newresource.ResourceAllocation;
52 import org.onosproject.net.newresource.ResourcePath;
53 import org.onosproject.net.newresource.ResourceService;
54 import org.onosproject.net.resource.device.IntentSetMultimap;
55 import org.onosproject.net.resource.link.LinkResourceAllocations;
56 import org.osgi.service.component.ComponentContext;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 import java.util.Collections;
61 import java.util.Dictionary;
62 import java.util.LinkedList;
63 import java.util.List;
64 import java.util.Optional;
67 import static com.google.common.base.Preconditions.checkArgument;
70 * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
72 // For now, remove component designation until dependency on the new resource manager is available.
73 // @Component(immediate = true)
74 public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> {
76 private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class);
78 private static final int DEFAULT_MAX_CAPACITY = 10;
80 @Property(name = "maxCapacity", intValue = DEFAULT_MAX_CAPACITY,
81 label = "Maximum utilization of an optical connection.")
83 private int maxCapacity = DEFAULT_MAX_CAPACITY;
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected ComponentConfigService cfgService;
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected IntentExtensionService intentManager;
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DeviceService deviceService;
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected ResourceService resourceService;
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected IntentSetMultimap intentSetMultimap;
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected IntentService intentService;
106 private ApplicationId appId;
109 public void modified(ComponentContext context) {
110 Dictionary properties = context.getProperties();
112 //TODO for reduction check if the new capacity is smaller than the size of the current mapping
113 String propertyString = Tools.get(properties, "maxCapacity");
115 //Ignore if propertyString is empty
116 if (!propertyString.isEmpty()) {
118 int temp = Integer.parseInt(propertyString);
119 //Ensure value is non-negative but allow zero as a way to shutdown the link
123 } catch (NumberFormatException e) {
124 //Malformed arguments lead to no change of value (user should be notified of error)
125 log.error("The value '{}' for maxCapacity was not parsable as an integer.", propertyString, e);
128 //Notify of empty value but do not return (other properties will also go in this function)
129 log.error("The value for maxCapacity was set to an empty value.");
135 public void activate(ComponentContext context) {
136 appId = coreService.registerApplication("org.onosproject.net.intent");
137 intentManager.registerCompiler(OpticalCircuitIntent.class, this);
138 cfgService.registerProperties(getClass());
143 public void deactivate() {
144 intentManager.unregisterCompiler(OpticalCircuitIntent.class);
145 cfgService.unregisterProperties(getClass(), false);
149 public List<Intent> compile(OpticalCircuitIntent intent, List<Intent> installable,
150 Set<LinkResourceAllocations> resources) {
151 // Check if ports are OduClt ports
152 ConnectPoint src = intent.getSrc();
153 ConnectPoint dst = intent.getDst();
154 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
155 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
156 checkArgument(srcPort instanceof OduCltPort);
157 checkArgument(dstPort instanceof OduCltPort);
159 log.debug("Compiling optical circuit intent between {} and {}", src, dst);
161 // Reserve OduClt ports
162 ResourcePath srcPortPath = new ResourcePath(src.deviceId(), src.port());
163 ResourcePath dstPortPath = new ResourcePath(dst.deviceId(), dst.port());
164 List<ResourceAllocation> allocation = resourceService.allocate(intent.id(), srcPortPath, dstPortPath);
165 if (allocation.isEmpty()) {
166 throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
169 LinkedList<Intent> intents = new LinkedList<>();
171 FlowRuleIntent circuitIntent;
172 OpticalConnectivityIntent connIntent = findOpticalConnectivityIntent(intent);
174 // Create optical connectivity intent if needed
175 if (connIntent == null) {
176 // Find OCh ports with available resources
177 Pair<OchPort, OchPort> ochPorts = findPorts(intent);
179 if (ochPorts == null) {
180 return Collections.emptyList();
183 // Create optical connectivity intent
184 ConnectPoint srcCP = new ConnectPoint(src.elementId(), ochPorts.getLeft().number());
185 ConnectPoint dstCP = new ConnectPoint(dst.elementId(), ochPorts.getRight().number());
186 // FIXME: hardcoded ODU signal type
187 connIntent = OpticalConnectivityIntent.builder()
191 .signalType(OduSignalType.ODU4)
192 .bidirectional(intent.isBidirectional())
194 intentService.submit(connIntent);
197 // Create optical circuit intent
198 List<FlowRule> rules = new LinkedList<>();
199 rules.add(connectPorts(src, connIntent.getSrc(), intent.priority()));
200 rules.add(connectPorts(connIntent.getDst(), dst, intent.priority()));
202 // Create flow rules for reverse path
203 if (intent.isBidirectional()) {
204 rules.add(connectPorts(connIntent.getSrc(), src, intent.priority()));
205 rules.add(connectPorts(dst, connIntent.getDst(), intent.priority()));
208 circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
210 // Save circuit to connectivity intent mapping
211 intentSetMultimap.allocateMapping(connIntent.id(), intent.id());
212 intents.add(circuitIntent);
218 * Checks if current allocations on given resource can satisfy request.
219 * If the resource is null, return true.
221 * @param resource the resource on which to map the intent
222 * @return true if the resource can accept the request, false otherwise
224 private boolean isAvailable(IntentId resource) {
225 if (resource == null) {
229 Set<IntentId> mapping = intentSetMultimap.getMapping(resource);
231 if (mapping == null) {
235 return mapping.size() < maxCapacity;
238 private boolean isAllowed(OpticalCircuitIntent circuitIntent, OpticalConnectivityIntent connIntent) {
239 ConnectPoint srcStaticPort = staticPort(circuitIntent.getSrc());
240 if (srcStaticPort != null) {
241 if (!srcStaticPort.equals(connIntent.getSrc())) {
246 ConnectPoint dstStaticPort = staticPort(circuitIntent.getDst());
247 if (dstStaticPort != null) {
248 if (!dstStaticPort.equals(connIntent.getDst())) {
257 * Returns existing and available optical connectivity intent that matches the given circuit intent.
259 * @param circuitIntent optical circuit intent
260 * @return existing optical connectivity intent, null otherwise.
262 private OpticalConnectivityIntent findOpticalConnectivityIntent(OpticalCircuitIntent circuitIntent) {
263 for (Intent intent : intentService.getIntents()) {
264 if (!(intent instanceof OpticalConnectivityIntent)) {
268 OpticalConnectivityIntent connIntent = (OpticalConnectivityIntent) intent;
270 ConnectPoint src = circuitIntent.getSrc();
271 ConnectPoint dst = circuitIntent.getDst();
272 // Ignore if the intents don't have identical src and dst devices
273 if (!src.deviceId().equals(connIntent.getSrc().deviceId()) &&
274 !dst.deviceId().equals(connIntent.getDst().deviceId())) {
278 if (!isAllowed(circuitIntent, connIntent)) {
282 if (isAvailable(connIntent.id())) {
290 private ConnectPoint staticPort(ConnectPoint connectPoint) {
291 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
293 String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT);
295 // FIXME: need a better way to match the port
296 if (staticPort != null) {
297 for (Port p : deviceService.getPorts(connectPoint.deviceId())) {
298 if (staticPort.equals(p.number().name())) {
299 return new ConnectPoint(p.element().id(), p.number());
307 private OchPort findAvailableOchPort(ConnectPoint oduPort) {
308 // First see if the port mappings are constrained
309 ConnectPoint ochCP = staticPort(oduPort);
312 OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port());
313 Optional<IntentId> intentId =
314 resourceService.getResourceAllocation(new ResourcePath(ochCP.deviceId(), ochCP.port()))
315 .map(ResourceAllocation::consumer)
316 .filter(x -> x instanceof IntentId)
317 .map(x -> (IntentId) x);
319 if (isAvailable(intentId.orElse(null))) {
324 // No port constraints, so find any port that works
325 List<Port> ports = deviceService.getPorts(oduPort.deviceId());
327 for (Port port : ports) {
328 if (!(port instanceof OchPort)) {
332 Optional<IntentId> intentId =
333 resourceService.getResourceAllocation(new ResourcePath(oduPort.deviceId(), port.number()))
334 .map(ResourceAllocation::consumer)
335 .filter(x -> x instanceof IntentId)
336 .map(x -> (IntentId) x);
337 if (isAvailable(intentId.orElse(null))) {
338 return (OchPort) port;
345 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) {
347 OchPort srcPort = findAvailableOchPort(intent.getSrc());
348 if (srcPort == null) {
352 OchPort dstPort = findAvailableOchPort(intent.getDst());
353 if (dstPort == null) {
357 return Pair.of(srcPort, dstPort);
361 * Builds flow rule for mapping between two ports.
363 * @param src source port
364 * @param dst destination port
367 private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst, int priority) {
368 checkArgument(src.deviceId().equals(dst.deviceId()));
370 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
371 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
373 selectorBuilder.matchInPort(src.port());
374 //selectorBuilder.add(Criteria.matchCltSignalType)
375 treatmentBuilder.setOutput(dst.port());
376 //treatmentBuilder.add(Instructions.modL1OduSignalType)
378 FlowRule flowRule = DefaultFlowRule.builder()
379 .forDevice(src.deviceId())
380 .withSelector(selectorBuilder.build())
381 .withTreatment(treatmentBuilder.build())
382 .withPriority(priority)