blob: 557288cb1ccb870f420facba21d3ac8eea559a08 [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;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.onosproject.core.ApplicationId;
25import org.onosproject.core.CoreService;
Marc De Leenheer723f5532015-06-03 20:16:17 -070026import org.onosproject.net.AnnotationKeys;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070027import org.onosproject.net.ConnectPoint;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -070028import org.onosproject.net.OchPort;
29import org.onosproject.net.OduCltPort;
30import org.onosproject.net.OduSignalType;
31import org.onosproject.net.Port;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.flow.DefaultFlowRule;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.FlowRule;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.intent.FlowRuleIntent;
40import org.onosproject.net.intent.Intent;
41import org.onosproject.net.intent.IntentCompiler;
42import org.onosproject.net.intent.IntentExtensionService;
43import org.onosproject.net.intent.IntentId;
44import org.onosproject.net.intent.IntentService;
45import org.onosproject.net.intent.OpticalCircuitIntent;
46import org.onosproject.net.intent.OpticalConnectivityIntent;
47import org.onosproject.net.intent.impl.IntentCompilationException;
48import org.onosproject.net.resource.device.DeviceResourceService;
49import org.onosproject.net.resource.link.LinkResourceAllocations;
50import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
52
53import java.util.Arrays;
54import java.util.Collections;
55import java.util.HashSet;
56import java.util.LinkedList;
57import java.util.List;
58import java.util.Set;
59
60import static com.google.common.base.Preconditions.checkArgument;
61
62/**
63 * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
64 */
65@Component(immediate = true)
66public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> {
67
68 private static final Logger log = LoggerFactory.getLogger(OpticalCircuitIntentCompiler.class);
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected IntentExtensionService intentManager;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected CoreService coreService;
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected DeviceService deviceService;
78
79 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected DeviceResourceService deviceResourceService;
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected IntentService intentService;
84
85 private ApplicationId appId;
86
87 @Activate
88 public void activate() {
89 appId = coreService.registerApplication("org.onosproject.net.intent");
90 intentManager.registerCompiler(OpticalCircuitIntent.class, this);
91 }
92
93 @Deactivate
94 public void deactivate() {
95 intentManager.unregisterCompiler(OpticalCircuitIntent.class);
96 }
97
98 @Override
99 public List<Intent> compile(OpticalCircuitIntent intent, List<Intent> installable,
100 Set<LinkResourceAllocations> resources) {
101 // Check if ports are OduClt ports
102 ConnectPoint src = intent.getSrc();
103 ConnectPoint dst = intent.getDst();
104 Port srcPort = deviceService.getPort(src.deviceId(), src.port());
105 Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
106 checkArgument(srcPort instanceof OduCltPort);
107 checkArgument(dstPort instanceof OduCltPort);
108
109 log.debug("Compiling optical circuit intent between {} and {}", src, dst);
110
111 // Reserve OduClt ports
112 if (!deviceResourceService.requestPorts(new HashSet(Arrays.asList(srcPort, dstPort)), intent)) {
113 throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
114 }
115
116 LinkedList<Intent> intents = new LinkedList<>();
117
118 FlowRuleIntent circuitIntent;
119 OpticalConnectivityIntent connIntent = findOpticalConnectivityIntent(intent);
120
121 // Create optical connectivity intent if needed
122 if (connIntent == null) {
123 // Find OCh ports with available resources
124 Pair<OchPort, OchPort> ochPorts = findPorts(intent);
125
126 if (ochPorts == null) {
127 return Collections.emptyList();
128 }
129
130 // Create optical connectivity intent
131 ConnectPoint srcCP = new ConnectPoint(src.elementId(), ochPorts.getLeft().number());
132 ConnectPoint dstCP = new ConnectPoint(dst.elementId(), ochPorts.getRight().number());
133 // FIXME: hardcoded ODU signal type
134 connIntent = OpticalConnectivityIntent.builder()
135 .appId(appId)
136 .src(srcCP)
137 .dst(dstCP)
138 .signalType(OduSignalType.ODU4)
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700139 .bidirectional(intent.isBidirectional())
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700140 .build();
Marc De Leenheer723f5532015-06-03 20:16:17 -0700141 intentService.submit(connIntent);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700142 }
143
144 // Create optical circuit intent
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700145 List<FlowRule> rules = new LinkedList<>();
146 rules.add(connectPorts(src, connIntent.getSrc()));
147 rules.add(connectPorts(connIntent.getDst(), dst));
148
149 // Create flow rules for reverse path
150 if (intent.isBidirectional()) {
151 rules.add(connectPorts(connIntent.getSrc(), src));
152 rules.add(connectPorts(dst, connIntent.getDst()));
153 }
154
155 circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700156
157 // Save circuit to connectivity intent mapping
Marc De Leenheer723f5532015-06-03 20:16:17 -0700158 deviceResourceService.requestMapping(connIntent.id(), intent.id());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700159 intents.add(circuitIntent);
160
161 return intents;
162 }
163
164 /**
165 * Checks if current allocations on given resource can satisfy request.
Marc De Leenheer723f5532015-06-03 20:16:17 -0700166 * If the resource is null, return true.
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700167 *
168 * @param request
169 * @param resource
170 * @return
171 */
172 private boolean isAvailable(Intent request, IntentId resource) {
Marc De Leenheer723f5532015-06-03 20:16:17 -0700173 if (resource == null) {
174 return true;
175 }
176
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700177 Set<IntentId> mapping = deviceResourceService.getMapping(resource);
178
Marc De Leenheer723f5532015-06-03 20:16:17 -0700179 if (mapping == null) {
180 return true;
181 }
182
183 // TODO: hardcoded 80% utilization
184 return mapping.size() < 8;
185 }
186
187 private boolean isAllowed(OpticalCircuitIntent circuitIntent, OpticalConnectivityIntent connIntent) {
188 ConnectPoint srcStaticPort = staticPort(circuitIntent.getSrc());
189 if (srcStaticPort != null) {
190 if (!srcStaticPort.equals(connIntent.getSrc())) {
191 return false;
192 }
193 }
194
195 ConnectPoint dstStaticPort = staticPort(circuitIntent.getDst());
196 if (dstStaticPort != null) {
197 if (!dstStaticPort.equals(connIntent.getDst())) {
198 return false;
199 }
200 }
201
202 return true;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700203 }
204
205 /**
206 * Returns existing and available optical connectivity intent that matches the given circuit intent.
207 *
208 * @param circuitIntent optical circuit intent
209 * @return existing optical connectivity intent, null otherwise.
210 */
211 private OpticalConnectivityIntent findOpticalConnectivityIntent(OpticalCircuitIntent circuitIntent) {
212 for (Intent intent : intentService.getIntents()) {
213 if (!(intent instanceof OpticalConnectivityIntent)) {
214 continue;
215 }
216
217 OpticalConnectivityIntent connIntent = (OpticalConnectivityIntent) intent;
218
219 ConnectPoint src = circuitIntent.getSrc();
220 ConnectPoint dst = circuitIntent.getDst();
Marc De Leenheer723f5532015-06-03 20:16:17 -0700221 // Ignore if the intents don't have identical src and dst devices
222 if (!src.deviceId().equals(connIntent.getSrc().deviceId()) &&
223 !dst.deviceId().equals(connIntent.getDst().deviceId())) {
224 continue;
225 }
226
227 if (!isAllowed(circuitIntent, connIntent)) {
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700228 continue;
229 }
230
231 if (isAvailable(circuitIntent, connIntent.id())) {
232 return connIntent;
233 }
234 }
235
236 return null;
237 }
238
Marc De Leenheer723f5532015-06-03 20:16:17 -0700239 private ConnectPoint staticPort(ConnectPoint connectPoint) {
240 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
241
242 String staticPort = port.annotations().value(AnnotationKeys.STATIC_PORT);
243
244 // FIXME: need a better way to match the port
245 if (staticPort != null) {
246 for (Port p : deviceService.getPorts(connectPoint.deviceId())) {
247 if (staticPort.equals(p.number().name())) {
248 return new ConnectPoint(p.element().id(), p.number());
249 }
250 }
251 }
252
253 return null;
254 }
255
256 private OchPort findAvailableOchPort(ConnectPoint oduPort, OpticalCircuitIntent circuitIntent) {
257 // First see if the port mappings are constrained
258 ConnectPoint ochCP = staticPort(oduPort);
259
260 if (ochCP != null) {
261 OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port());
262 IntentId intentId = deviceResourceService.getAllocations(ochPort);
263 if (isAvailable(circuitIntent, intentId)) {
264 return ochPort;
265 }
266 }
267
268 // No port constraints, so find any port that works
269 List<Port> ports = deviceService.getPorts(oduPort.deviceId());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700270
271 for (Port port : ports) {
272 if (!(port instanceof OchPort)) {
273 continue;
274 }
275
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700276 IntentId intentId = deviceResourceService.getAllocations(port);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700277 if (isAvailable(circuitIntent, intentId)) {
278 return (OchPort) port;
279 }
280 }
281
282 return null;
283 }
284
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700285 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) {
286
Marc De Leenheer723f5532015-06-03 20:16:17 -0700287 OchPort srcPort = findAvailableOchPort(intent.getSrc(), intent);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700288 if (srcPort == null) {
289 return null;
290 }
291
Marc De Leenheer723f5532015-06-03 20:16:17 -0700292 OchPort dstPort = findAvailableOchPort(intent.getDst(), intent);
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700293 if (dstPort == null) {
294 return null;
295 }
296
297 return Pair.of(srcPort, dstPort);
298 }
299
300 /**
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700301 * Builds flow rule for mapping between two ports.
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700302 *
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700303 * @param src source port
304 * @param dst destination port
305 * @return flow rules
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700306 */
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700307 private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst) {
308 checkArgument(src.deviceId().equals(dst.deviceId()));
309
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700310 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
311 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
312
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700313 selectorBuilder.matchInPort(src.port());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700314 //selectorBuilder.add(Criteria.matchCltSignalType)
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700315 treatmentBuilder.setOutput(dst.port());
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700316 //treatmentBuilder.add(Instructions.modL1OduSignalType)
317
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700318 FlowRule flowRule = DefaultFlowRule.builder()
319 .forDevice(src.deviceId())
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700320 .withSelector(selectorBuilder.build())
321 .withTreatment(treatmentBuilder.build())
322 .withPriority(100)
323 .fromApp(appId)
324 .makePermanent()
325 .build();
326
Marc De Leenheer4a1c1fa2015-06-01 18:08:56 -0700327 return flowRule;
Marc De Leenheer8c2caac2015-05-28 16:37:33 -0700328 }
329}