blob: 2c547ea348abec0c6b640b13c074f86f87cc4cca [file] [log] [blame]
Marc De Leenheer8c2caac2015-05-28 16:37:33 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16package org.onosproject.net.intent.impl.compiler;
17
18import org.apache.commons.lang3.tuple.Pair;
19import org.apache.felix.scr.annotations.Activate;
Sho SHIMIZU9a2b8292015-10-28 13:00:16 -070020import org.apache.felix.scr.annotations.Component;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070021import org.apache.felix.scr.annotations.Deactivate;
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -070022import org.apache.felix.scr.annotations.Modified;
23import org.apache.felix.scr.annotations.Property;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070024import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -070026import org.onlab.util.Tools;
27import org.onosproject.cfg.ComponentConfigService;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Marc De Leenheer723f5532015-06-03 20:16:17 -070030import org.onosproject.net.AnnotationKeys;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070031import org.onosproject.net.ConnectPoint;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070032import org.onosproject.net.OchPort;
33import org.onosproject.net.OduCltPort;
34import org.onosproject.net.OduSignalType;
35import org.onosproject.net.Port;
36import org.onosproject.net.device.DeviceService;
37import org.onosproject.net.flow.DefaultFlowRule;
38import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.FlowRule;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.intent.FlowRuleIntent;
44import org.onosproject.net.intent.Intent;
45import org.onosproject.net.intent.IntentCompiler;
46import org.onosproject.net.intent.IntentExtensionService;
47import org.onosproject.net.intent.IntentId;
48import org.onosproject.net.intent.IntentService;
49import org.onosproject.net.intent.OpticalCircuitIntent;
50import org.onosproject.net.intent.OpticalConnectivityIntent;
51import org.onosproject.net.intent.impl.IntentCompilationException;
Sho SHIMIZU5c16df82015-09-29 12:52:07 -070052import org.onosproject.net.newresource.ResourceAllocation;
53import org.onosproject.net.newresource.ResourcePath;
54import org.onosproject.net.newresource.ResourceService;
Sho SHIMIZU7d20af12015-10-01 16:03:51 -070055import org.onosproject.net.resource.device.IntentSetMultimap;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070056import org.onosproject.net.resource.link.LinkResourceAllocations;
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -070057import org.osgi.service.component.ComponentContext;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070061import java.util.Collections;
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -070062import java.util.Dictionary;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070063import java.util.LinkedList;
64import java.util.List;
Sho SHIMIZU5c16df82015-09-29 12:52:07 -070065import java.util.Optional;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070066import java.util.Set;
67
68import static com.google.common.base.Preconditions.checkArgument;
69
70/**
71 * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
72 */
Ray Milkeye6099412015-10-05 10:53:17 -070073// For now, remove component designation until dependency on the new resource manager is available.
Sho SHIMIZU9a2b8292015-10-28 13:00:16 -070074@Component(immediate = true)
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070075public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> {
76
77 private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class);
78
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -070079 private static final int DEFAULT_MAX_CAPACITY = 10;
80
81 @Property(name = "maxCapacity", intValue = DEFAULT_MAX_CAPACITY,
82 label = "Maximum utilization of an optical connection.")
83
84 private int maxCapacity = DEFAULT_MAX_CAPACITY;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected ComponentConfigService cfgService;
88
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected IntentExtensionService intentManager;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected DeviceService deviceService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU5c16df82015-09-29 12:52:07 -070099 protected ResourceService resourceService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Sho SHIMIZU7d20af12015-10-01 16:03:51 -0700102 protected IntentSetMultimap intentSetMultimap;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected IntentService intentService;
106
107 private ApplicationId appId;
108
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -0700109 @Modified
110 public void modified(ComponentContext context) {
111 Dictionary properties = context.getProperties();
112
113 //TODO for reduction check if the new capacity is smaller than the size of the current mapping
114 String propertyString = Tools.get(properties, "maxCapacity");
115
116 //Ignore if propertyString is empty
117 if (!propertyString.isEmpty()) {
118 try {
119 int temp = Integer.parseInt(propertyString);
120 //Ensure value is non-negative but allow zero as a way to shutdown the link
121 if (temp >= 0) {
122 maxCapacity = temp;
123 }
124 } catch (NumberFormatException e) {
125 //Malformed arguments lead to no change of value (user should be notified of error)
126 log.error("The value '{}' for maxCapacity was not parsable as an integer.", propertyString, e);
127 }
128 } else {
129 //Notify of empty value but do not return (other properties will also go in this function)
130 log.error("The value for maxCapacity was set to an empty value.");
131 }
132
133 }
134
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700135 @Activate
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -0700136 public void activate(ComponentContext context) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700137 appId = coreService.registerApplication("org.onosproject.net.intent");
138 intentManager.registerCompiler(OpticalCircuitIntent.class, this);
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -0700139 cfgService.registerProperties(getClass());
140 modified(context);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700141 }
142
143 @Deactivate
144 public void deactivate() {
145 intentManager.unregisterCompiler(OpticalCircuitIntent.class);
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -0700146 cfgService.unregisterProperties(getClass(), false);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700147 }
148
149 @Override
150 public List<Intent> compile(OpticalCircuitIntent intent, List<Intent> installable,
151 Set<LinkResourceAllocations> resources) {
152 // Check if ports are OduClt ports
153 ConnectPoint src = intent.getSrc();
154 ConnectPoint dst = intent.getDst();
155 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
156 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
157 checkArgument(srcPort instanceof OduCltPort);
158 checkArgument(dstPort instanceof OduCltPort);
159
160 log.debug("Compiling optical circuit intent between {} and {}", src, dst);
161
162 // Reserve OduClt ports
Sho SHIMIZU60ac58e2015-11-11 12:16:38 -0800163 ResourcePath srcPortPath = ResourcePath.discrete(src.deviceId(), src.port());
164 ResourcePath dstPortPath = ResourcePath.discrete(dst.deviceId(), dst.port());
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700165 List<ResourceAllocation> allocation = resourceService.allocate(intent.id(), srcPortPath, dstPortPath);
166 if (allocation.isEmpty()) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700167 throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
168 }
169
170 LinkedList<Intent> intents = new LinkedList<>();
171
172 FlowRuleIntent circuitIntent;
173 OpticalConnectivityIntent connIntent = findOpticalConnectivityIntent(intent);
174
175 // Create optical connectivity intent if needed
176 if (connIntent == null) {
177 // Find OCh ports with available resources
178 Pair<OchPort, OchPort> ochPorts = findPorts(intent);
179
180 if (ochPorts == null) {
181 return Collections.emptyList();
182 }
183
184 // Create optical connectivity intent
185 ConnectPoint srcCP = new ConnectPoint(src.elementId(), ochPorts.getLeft().number());
186 ConnectPoint dstCP = new ConnectPoint(dst.elementId(), ochPorts.getRight().number());
187 // FIXME: hardcoded ODU signal type
188 connIntent = OpticalConnectivityIntent.builder()
189 .appId(appId)
190 .src(srcCP)
191 .dst(dstCP)
192 .signalType(OduSignalType.ODU4)
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700193 .bidirectional(intent.isBidirectional())
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700194 .build();
Marc De Leenheer723f5532015-06-03 20:16:17 -0700195 intentService.submit(connIntent);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700196 }
197
198 // Create optical circuit intent
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700199 List<FlowRule> rules = new LinkedList<>();
Brian O'Connor81134662015-06-25 17:23:33 -0400200 rules.add(connectPorts(src, connIntent.getSrc(), intent.priority()));
201 rules.add(connectPorts(connIntent.getDst(), dst, intent.priority()));
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700202
203 // Create flow rules for reverse path
204 if (intent.isBidirectional()) {
Brian O'Connor81134662015-06-25 17:23:33 -0400205 rules.add(connectPorts(connIntent.getSrc(), src, intent.priority()));
206 rules.add(connectPorts(dst, connIntent.getDst(), intent.priority()));
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700207 }
208
209 circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700210
211 // Save circuit to connectivity intent mapping
Sho SHIMIZU7d20af12015-10-01 16:03:51 -0700212 intentSetMultimap.allocateMapping(connIntent.id(), intent.id());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700213 intents.add(circuitIntent);
214
215 return intents;
216 }
217
218 /**
219 * Checks if current allocations on given resource can satisfy request.
Marc De Leenheer723f5532015-06-03 20:16:17 -0700220 * If the resource is null, return true.
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700221 *
Marc De Leenheerc9733082015-06-04 12:22:38 -0700222 * @param resource the resource on which to map the intent
223 * @return true if the resource can accept the request, false otherwise
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700224 */
Sho SHIMIZU0f9a68c2015-09-29 12:45:36 -0700225 private boolean isAvailable(IntentId resource) {
Marc De Leenheer723f5532015-06-03 20:16:17 -0700226 if (resource == null) {
227 return true;
228 }
229
Sho SHIMIZU7d20af12015-10-01 16:03:51 -0700230 Set<IntentId> mapping = intentSetMultimap.getMapping(resource);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700231
Marc De Leenheer723f5532015-06-03 20:16:17 -0700232 if (mapping == null) {
233 return true;
234 }
235
Aaron Kruglikov6490a3b2015-06-05 14:25:32 -0700236 return mapping.size() < maxCapacity;
Marc De Leenheer723f5532015-06-03 20:16:17 -0700237 }
238
239 private boolean isAllowed(OpticalCircuitIntent circuitIntent, OpticalConnectivityIntent connIntent) {
240 ConnectPoint srcStaticPort = staticPort(circuitIntent.getSrc());
241 if (srcStaticPort != null) {
242 if (!srcStaticPort.equals(connIntent.getSrc())) {
243 return false;
244 }
245 }
246
247 ConnectPoint dstStaticPort = staticPort(circuitIntent.getDst());
248 if (dstStaticPort != null) {
249 if (!dstStaticPort.equals(connIntent.getDst())) {
250 return false;
251 }
252 }
253
254 return true;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700255 }
256
257 /**
258 * Returns existing and available optical connectivity intent that matches the given circuit intent.
259 *
260 * @param circuitIntent optical circuit intent
261 * @return existing optical connectivity intent, null otherwise.
262 */
263 private OpticalConnectivityIntent findOpticalConnectivityIntent(OpticalCircuitIntent circuitIntent) {
264 for (Intent intent : intentService.getIntents()) {
265 if (!(intent instanceof OpticalConnectivityIntent)) {
266 continue;
267 }
268
269 OpticalConnectivityIntent connIntent = (OpticalConnectivityIntent) intent;
270
271 ConnectPoint src = circuitIntent.getSrc();
272 ConnectPoint dst = circuitIntent.getDst();
Marc De Leenheer723f5532015-06-03 20:16:17 -0700273 // Ignore if the intents don't have identical src and dst devices
274 if (!src.deviceId().equals(connIntent.getSrc().deviceId()) &&
275 !dst.deviceId().equals(connIntent.getDst().deviceId())) {
276 continue;
277 }
278
279 if (!isAllowed(circuitIntent, connIntent)) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700280 continue;
281 }
282
Sho SHIMIZU0f9a68c2015-09-29 12:45:36 -0700283 if (isAvailable(connIntent.id())) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700284 return connIntent;
285 }
286 }
287
288 return null;
289 }
290
Marc De Leenheer723f5532015-06-03 20:16:17 -0700291 private ConnectPoint staticPort(ConnectPoint connectPoint) {
292 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
293
294 String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT);
295
296 // FIXME: need a better way to match the port
297 if (staticPort != null) {
298 for (Port p : deviceService.getPorts(connectPoint.deviceId())) {
299 if (staticPort.equals(p.number().name())) {
300 return new ConnectPoint(p.element().id(), p.number());
301 }
302 }
303 }
304
305 return null;
306 }
307
Sho SHIMIZUd5bdbf82015-09-29 12:46:09 -0700308 private OchPort findAvailableOchPort(ConnectPoint oduPort) {
Marc De Leenheer723f5532015-06-03 20:16:17 -0700309 // First see if the port mappings are constrained
310 ConnectPoint ochCP = staticPort(oduPort);
311
312 if (ochCP != null) {
313 OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port());
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700314 Optional<IntentId> intentId =
Sho SHIMIZU60ac58e2015-11-11 12:16:38 -0800315 resourceService.getResourceAllocation(ResourcePath.discrete(ochCP.deviceId(), ochCP.port()))
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800316 .stream()
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700317 .map(ResourceAllocation::consumer)
318 .filter(x -> x instanceof IntentId)
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800319 .map(x -> (IntentId) x)
320 .findAny();
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700321
322 if (isAvailable(intentId.orElse(null))) {
Marc De Leenheer723f5532015-06-03 20:16:17 -0700323 return ochPort;
324 }
325 }
326
327 // No port constraints, so find any port that works
328 List<Port> ports = deviceService.getPorts(oduPort.deviceId());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700329
330 for (Port port : ports) {
331 if (!(port instanceof OchPort)) {
332 continue;
333 }
334
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700335 Optional<IntentId> intentId =
Sho SHIMIZU60ac58e2015-11-11 12:16:38 -0800336 resourceService.getResourceAllocation(ResourcePath.discrete(oduPort.deviceId(), port.number()))
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800337 .stream()
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700338 .map(ResourceAllocation::consumer)
339 .filter(x -> x instanceof IntentId)
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800340 .map(x -> (IntentId) x)
341 .findAny();
342
Sho SHIMIZU5c16df82015-09-29 12:52:07 -0700343 if (isAvailable(intentId.orElse(null))) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700344 return (OchPort) port;
345 }
346 }
347
348 return null;
349 }
350
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700351 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) {
352
Sho SHIMIZUd5bdbf82015-09-29 12:46:09 -0700353 OchPort srcPort = findAvailableOchPort(intent.getSrc());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700354 if (srcPort == null) {
355 return null;
356 }
357
Sho SHIMIZUd5bdbf82015-09-29 12:46:09 -0700358 OchPort dstPort = findAvailableOchPort(intent.getDst());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700359 if (dstPort == null) {
360 return null;
361 }
362
363 return Pair.of(srcPort, dstPort);
364 }
365
366 /**
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700367 * Builds flow rule for mapping between two ports.
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700368 *
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700369 * @param src source port
370 * @param dst destination port
371 * @return flow rules
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700372 */
Brian O'Connor81134662015-06-25 17:23:33 -0400373 private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst, int priority) {
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700374 checkArgument(src.deviceId().equals(dst.deviceId()));
375
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700376 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
377 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
378
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700379 selectorBuilder.matchInPort(src.port());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700380 //selectorBuilder.add(Criteria.matchCltSignalType)
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700381 treatmentBuilder.setOutput(dst.port());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700382 //treatmentBuilder.add(Instructions.modL1OduSignalType)
383
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700384 FlowRule flowRule = DefaultFlowRule.builder()
385 .forDevice(src.deviceId())
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700386 .withSelector(selectorBuilder.build())
387 .withTreatment(treatmentBuilder.build())
Brian O'Connor81134662015-06-25 17:23:33 -0400388 .withPriority(priority)
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700389 .fromApp(appId)
390 .makePermanent()
391 .build();
392
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700393 return flowRule;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700394 }
395}