Rimon Ashkenazy
Committed by Gerrit Code Review

[ONOS-2476]: Circuit intent support for ODU Multiplexing

Change-Id: I37229e7107e38baf8416102598f27004ef319665
...@@ -27,6 +27,8 @@ import org.onosproject.net.intent.IntentService; ...@@ -27,6 +27,8 @@ import org.onosproject.net.intent.IntentService;
27 import org.onosproject.net.intent.IntentState; 27 import org.onosproject.net.intent.IntentState;
28 import org.onosproject.net.intent.LinkCollectionIntent; 28 import org.onosproject.net.intent.LinkCollectionIntent;
29 import org.onosproject.net.intent.MultiPointToSinglePointIntent; 29 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
30 +import org.onosproject.net.intent.OpticalCircuitIntent;
31 +import org.onosproject.net.intent.OpticalConnectivityIntent;
30 import org.onosproject.net.intent.PathIntent; 32 import org.onosproject.net.intent.PathIntent;
31 import org.onosproject.net.intent.PointToPointIntent; 33 import org.onosproject.net.intent.PointToPointIntent;
32 import org.onosproject.net.intent.SinglePointToMultiPointIntent; 34 import org.onosproject.net.intent.SinglePointToMultiPointIntent;
...@@ -114,6 +116,8 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -114,6 +116,8 @@ public class IntentsListCommand extends AbstractShellCommand {
114 private IntentSummary summarySinglePointToMultiPoint; 116 private IntentSummary summarySinglePointToMultiPoint;
115 private IntentSummary summaryPath; 117 private IntentSummary summaryPath;
116 private IntentSummary summaryLinkCollection; 118 private IntentSummary summaryLinkCollection;
119 + private IntentSummary summaryOpticalCircuit;
120 + private IntentSummary summaryOpticalConnectivity;
117 private IntentSummary summaryUnknownType; 121 private IntentSummary summaryUnknownType;
118 122
119 /** 123 /**
...@@ -130,6 +134,8 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -130,6 +134,8 @@ public class IntentsListCommand extends AbstractShellCommand {
130 new IntentSummary("SinglePointToMultiPoint"); 134 new IntentSummary("SinglePointToMultiPoint");
131 summaryPath = new IntentSummary("Path"); 135 summaryPath = new IntentSummary("Path");
132 summaryLinkCollection = new IntentSummary("LinkCollection"); 136 summaryLinkCollection = new IntentSummary("LinkCollection");
137 + summaryOpticalCircuit = new IntentSummary("OpticalCircuit");
138 + summaryOpticalConnectivity = new IntentSummary("OpticalConnectivity");
133 summaryUnknownType = new IntentSummary("UnknownType"); 139 summaryUnknownType = new IntentSummary("UnknownType");
134 } 140 }
135 141
...@@ -182,7 +188,14 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -182,7 +188,14 @@ public class IntentsListCommand extends AbstractShellCommand {
182 summaryLinkCollection.update(intentState); 188 summaryLinkCollection.update(intentState);
183 continue; 189 continue;
184 } 190 }
185 - 191 + if (intent instanceof OpticalCircuitIntent) {
192 + summaryOpticalCircuit.update(intentState);
193 + continue;
194 + }
195 + if (intent instanceof OpticalConnectivityIntent) {
196 + summaryOpticalConnectivity.update(intentState);
197 + continue;
198 + }
186 summaryUnknownType.update(intentState); 199 summaryUnknownType.update(intentState);
187 } 200 }
188 } 201 }
...@@ -204,6 +217,8 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -204,6 +217,8 @@ public class IntentsListCommand extends AbstractShellCommand {
204 summarySinglePointToMultiPoint.json(mapper)); 217 summarySinglePointToMultiPoint.json(mapper));
205 result.set("path", summaryPath.json(mapper)); 218 result.set("path", summaryPath.json(mapper));
206 result.set("linkCollection", summaryLinkCollection.json(mapper)); 219 result.set("linkCollection", summaryLinkCollection.json(mapper));
220 + result.set("opticalCircuit", summaryOpticalCircuit.json(mapper));
221 + result.set("opticalConnectivity", summaryOpticalConnectivity.json(mapper));
207 result.set("unknownType", summaryUnknownType.json(mapper)); 222 result.set("unknownType", summaryUnknownType.json(mapper));
208 result.set("all", summaryAll.json(mapper)); 223 result.set("all", summaryAll.json(mapper));
209 return result; 224 return result;
...@@ -220,6 +235,8 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -220,6 +235,8 @@ public class IntentsListCommand extends AbstractShellCommand {
220 summarySinglePointToMultiPoint.printState(); 235 summarySinglePointToMultiPoint.printState();
221 summaryPath.printState(); 236 summaryPath.printState();
222 summaryLinkCollection.printState(); 237 summaryLinkCollection.printState();
238 + summaryOpticalCircuit.printState();
239 + summaryOpticalConnectivity.printState();
223 summaryUnknownType.printState(); 240 summaryUnknownType.printState();
224 summaryAll.printState(); 241 summaryAll.printState();
225 } 242 }
...@@ -378,6 +395,12 @@ public class IntentsListCommand extends AbstractShellCommand { ...@@ -378,6 +395,12 @@ public class IntentsListCommand extends AbstractShellCommand {
378 LinkCollectionIntent li = (LinkCollectionIntent) intent; 395 LinkCollectionIntent li = (LinkCollectionIntent) intent;
379 print(" links=%s", li.links()); 396 print(" links=%s", li.links());
380 print(" egress=%s", li.egressPoints()); 397 print(" egress=%s", li.egressPoints());
398 + } else if (intent instanceof OpticalCircuitIntent) {
399 + OpticalCircuitIntent ci = (OpticalCircuitIntent) intent;
400 + print(" src=%s, dst=%s", ci.getSrc(), ci.getDst());
401 + } else if (intent instanceof OpticalConnectivityIntent) {
402 + OpticalConnectivityIntent ci = (OpticalConnectivityIntent) intent;
403 + print(" src=%s, dst=%s", ci.getSrc(), ci.getDst());
381 } 404 }
382 405
383 List<Intent> installable = service.getInstallableIntents(intent.key()); 406 List<Intent> installable = service.getInstallableIntents(intent.key());
......
...@@ -45,4 +45,14 @@ public enum OduSignalType { ...@@ -45,4 +45,14 @@ public enum OduSignalType {
45 public long bitRate() { 45 public long bitRate() {
46 return this.bitRate; 46 return this.bitRate;
47 } 47 }
48 +
49 + /**
50 + * Returns the number of tributary slots of the OduSignalType.
51 + * Each TributarySlot is 1.25Gbps.
52 + * @return number of tributary slots
53 + */
54 + public int tributarySlots() {
55 + return (int) (this.bitRate() / OduSignalType.ODU0.bitRate());
56 + }
57 +
48 } 58 }
......
...@@ -28,18 +28,27 @@ import org.onosproject.cfg.ComponentConfigService; ...@@ -28,18 +28,27 @@ import org.onosproject.cfg.ComponentConfigService;
28 import org.onosproject.core.ApplicationId; 28 import org.onosproject.core.ApplicationId;
29 import org.onosproject.core.CoreService; 29 import org.onosproject.core.CoreService;
30 import org.onosproject.net.AnnotationKeys; 30 import org.onosproject.net.AnnotationKeys;
31 +import org.onosproject.net.CltSignalType;
31 import org.onosproject.net.ConnectPoint; 32 import org.onosproject.net.ConnectPoint;
33 +import org.onosproject.net.DeviceId;
32 import org.onosproject.net.OchPort; 34 import org.onosproject.net.OchPort;
33 import org.onosproject.net.OduCltPort; 35 import org.onosproject.net.OduCltPort;
36 +import org.onosproject.net.OduSignalId;
34 import org.onosproject.net.OduSignalType; 37 import org.onosproject.net.OduSignalType;
35 import org.onosproject.net.Port; 38 import org.onosproject.net.Port;
39 +import org.onosproject.net.TributarySlot;
40 +import org.onosproject.net.behaviour.TributarySlotQuery;
36 import org.onosproject.net.device.DeviceService; 41 import org.onosproject.net.device.DeviceService;
42 +import org.onosproject.net.driver.Driver;
43 +import org.onosproject.net.driver.DriverService;
37 import org.onosproject.net.flow.DefaultFlowRule; 44 import org.onosproject.net.flow.DefaultFlowRule;
38 import org.onosproject.net.flow.DefaultTrafficSelector; 45 import org.onosproject.net.flow.DefaultTrafficSelector;
39 import org.onosproject.net.flow.DefaultTrafficTreatment; 46 import org.onosproject.net.flow.DefaultTrafficTreatment;
40 import org.onosproject.net.flow.FlowRule; 47 import org.onosproject.net.flow.FlowRule;
41 import org.onosproject.net.flow.TrafficSelector; 48 import org.onosproject.net.flow.TrafficSelector;
42 import org.onosproject.net.flow.TrafficTreatment; 49 import org.onosproject.net.flow.TrafficTreatment;
50 +import org.onosproject.net.flow.criteria.Criteria;
51 +import org.onosproject.net.flow.instructions.Instructions;
43 import org.onosproject.net.intent.FlowRuleIntent; 52 import org.onosproject.net.intent.FlowRuleIntent;
44 import org.onosproject.net.intent.Intent; 53 import org.onosproject.net.intent.Intent;
45 import org.onosproject.net.intent.IntentCompiler; 54 import org.onosproject.net.intent.IntentCompiler;
...@@ -59,19 +68,22 @@ import org.osgi.service.component.ComponentContext; ...@@ -59,19 +68,22 @@ import org.osgi.service.component.ComponentContext;
59 import org.slf4j.Logger; 68 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory; 69 import org.slf4j.LoggerFactory;
61 70
71 +import com.google.common.collect.ImmutableList;
72 +import com.google.common.collect.Sets;
73 +
62 import java.util.Collections; 74 import java.util.Collections;
63 import java.util.Dictionary; 75 import java.util.Dictionary;
64 import java.util.LinkedList; 76 import java.util.LinkedList;
65 import java.util.List; 77 import java.util.List;
66 import java.util.Optional; 78 import java.util.Optional;
67 import java.util.Set; 79 import java.util.Set;
80 +import java.util.stream.Collectors;
68 81
69 import static com.google.common.base.Preconditions.checkArgument; 82 import static com.google.common.base.Preconditions.checkArgument;
70 83
71 /** 84 /**
72 * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}. 85 * An intent compiler for {@link org.onosproject.net.intent.OpticalCircuitIntent}.
73 */ 86 */
74 -// For now, remove component designation until dependency on the new resource manager is available.
75 @Component(immediate = true) 87 @Component(immediate = true)
76 public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> { 88 public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircuitIntent> {
77 89
...@@ -105,6 +117,9 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -105,6 +117,9 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected IntentService intentService; 118 protected IntentService intentService;
107 119
120 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 + protected DriverService driverService;
122 +
108 private ApplicationId appId; 123 private ApplicationId appId;
109 124
110 @Modified 125 @Modified
...@@ -160,6 +175,11 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -160,6 +175,11 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
160 175
161 log.debug("Compiling optical circuit intent between {} and {}", src, dst); 176 log.debug("Compiling optical circuit intent between {} and {}", src, dst);
162 177
178 + // Release of intent resources here is only a temporary solution for handling the
179 + // case of recompiling due to intent restoration (when intent state is FAILED).
180 + // TODO: try to release intent resources in IntentManager.
181 + resourceService.release(intent.id());
182 +
163 // Reserve OduClt ports 183 // Reserve OduClt ports
164 Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource(); 184 Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource();
165 Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource(); 185 Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource();
...@@ -168,29 +188,50 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -168,29 +188,50 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
168 throw new IntentCompilationException("Unable to reserve ports for intent " + intent); 188 throw new IntentCompilationException("Unable to reserve ports for intent " + intent);
169 } 189 }
170 190
191 + // Check if both devices support multiplexing (usage of TributarySlots)
192 + boolean multiplexingSupported = isMultiplexingSupported(intent);
193 +
171 LinkedList<Intent> intents = new LinkedList<>(); 194 LinkedList<Intent> intents = new LinkedList<>();
195 + // slots are used only for devices supporting multiplexing
196 + Set<TributarySlot> slots = Collections.emptySet();
172 197
173 - FlowRuleIntent circuitIntent; 198 + OpticalConnectivityIntent connIntent = findOpticalConnectivityIntent(intent, multiplexingSupported);
174 - OpticalConnectivityIntent connIntent = findOpticalConnectivityIntent(intent); 199 + if ((connIntent != null) && multiplexingSupported) {
200 + // Allocate TributarySlots on existing OCH ports
201 + slots = assignTributarySlots(intent, Pair.of(connIntent.getSrc(), connIntent.getDst()));
202 + }
175 203
176 - // Create optical connectivity intent if needed 204 + // Create optical connectivity intent if needed - no optical intent or not enough slots available
177 - if (connIntent == null) { 205 + if (connIntent == null || (multiplexingSupported && slots.isEmpty())) {
178 // Find OCh ports with available resources 206 // Find OCh ports with available resources
179 Pair<OchPort, OchPort> ochPorts = findPorts(intent); 207 Pair<OchPort, OchPort> ochPorts = findPorts(intent);
180 208
181 if (ochPorts == null) { 209 if (ochPorts == null) {
182 - return Collections.emptyList(); 210 + // Release port allocations if unsuccessful
211 + resourceService.release(intent.id());
212 + throw new IntentCompilationException("Unable to find suitable OCH ports for intent " + intent);
183 } 213 }
184 214
185 - // Create optical connectivity intent
186 ConnectPoint srcCP = new ConnectPoint(src.elementId(), ochPorts.getLeft().number()); 215 ConnectPoint srcCP = new ConnectPoint(src.elementId(), ochPorts.getLeft().number());
187 ConnectPoint dstCP = new ConnectPoint(dst.elementId(), ochPorts.getRight().number()); 216 ConnectPoint dstCP = new ConnectPoint(dst.elementId(), ochPorts.getRight().number());
188 - // FIXME: hardcoded ODU signal type 217 +
218 + if (multiplexingSupported) {
219 + // Allocate TributarySlots on OCH ports
220 + slots = assignTributarySlots(intent, Pair.of(srcCP, dstCP));
221 + if (slots.isEmpty()) {
222 + // Release port allocations if unsuccessful
223 + resourceService.release(intent.id());
224 + throw new IntentCompilationException("Unable to find Tributary Slots for intent " + intent);
225 + }
226 + }
227 +
228 + // Create optical connectivity intent
229 + OduSignalType signalType = ochPorts.getLeft().signalType();
189 connIntent = OpticalConnectivityIntent.builder() 230 connIntent = OpticalConnectivityIntent.builder()
190 .appId(appId) 231 .appId(appId)
191 .src(srcCP) 232 .src(srcCP)
192 .dst(dstCP) 233 .dst(dstCP)
193 - .signalType(OduSignalType.ODU4) 234 + .signalType(signalType)
194 .bidirectional(intent.isBidirectional()) 235 .bidirectional(intent.isBidirectional())
195 .build(); 236 .build();
196 intentService.submit(connIntent); 237 intentService.submit(connIntent);
...@@ -198,16 +239,20 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -198,16 +239,20 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
198 239
199 // Create optical circuit intent 240 // Create optical circuit intent
200 List<FlowRule> rules = new LinkedList<>(); 241 List<FlowRule> rules = new LinkedList<>();
201 - rules.add(connectPorts(src, connIntent.getSrc(), intent.priority())); 242 + // at the source: ODUCLT port mapping to OCH port
202 - rules.add(connectPorts(connIntent.getDst(), dst, intent.priority())); 243 + rules.add(connectPorts(src, connIntent.getSrc(), intent.priority(), slots));
244 + // at the destination: OCH port mapping to ODUCLT port
245 + rules.add(connectPorts(connIntent.getDst(), dst, intent.priority(), slots));
203 246
204 // Create flow rules for reverse path 247 // Create flow rules for reverse path
205 if (intent.isBidirectional()) { 248 if (intent.isBidirectional()) {
206 - rules.add(connectPorts(connIntent.getSrc(), src, intent.priority())); 249 + // at the destination: OCH port mapping to ODUCLT port
207 - rules.add(connectPorts(dst, connIntent.getDst(), intent.priority())); 250 + rules.add(connectPorts(connIntent.getSrc(), src, intent.priority(), slots));
251 + // at the source: ODUCLT port mapping to OCH port
252 + rules.add(connectPorts(dst, connIntent.getDst(), intent.priority(), slots));
208 } 253 }
209 254
210 - circuitIntent = new FlowRuleIntent(appId, rules, intent.resources()); 255 + FlowRuleIntent circuitIntent = new FlowRuleIntent(appId, rules, intent.resources());
211 256
212 // Save circuit to connectivity intent mapping 257 // Save circuit to connectivity intent mapping
213 intentSetMultimap.allocateMapping(connIntent.id(), intent.id()); 258 intentSetMultimap.allocateMapping(connIntent.id(), intent.id());
...@@ -259,9 +304,14 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -259,9 +304,14 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
259 * Returns existing and available optical connectivity intent that matches the given circuit intent. 304 * Returns existing and available optical connectivity intent that matches the given circuit intent.
260 * 305 *
261 * @param circuitIntent optical circuit intent 306 * @param circuitIntent optical circuit intent
307 + * @param multiplexingSupported indicates whether ODU multiplexing is supported
262 * @return existing optical connectivity intent, null otherwise. 308 * @return existing optical connectivity intent, null otherwise.
263 */ 309 */
264 - private OpticalConnectivityIntent findOpticalConnectivityIntent(OpticalCircuitIntent circuitIntent) { 310 + private OpticalConnectivityIntent findOpticalConnectivityIntent(OpticalCircuitIntent circuitIntent,
311 + boolean multiplexingSupported) {
312 +
313 + OduSignalType oduSignalType = mappingCltSignalTypeToOduSignalType(circuitIntent.getSignalType());
314 +
265 for (Intent intent : intentService.getIntents()) { 315 for (Intent intent : intentService.getIntents()) {
266 if (!(intent instanceof OpticalConnectivityIntent)) { 316 if (!(intent instanceof OpticalConnectivityIntent)) {
267 continue; 317 continue;
...@@ -272,7 +322,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -272,7 +322,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
272 ConnectPoint src = circuitIntent.getSrc(); 322 ConnectPoint src = circuitIntent.getSrc();
273 ConnectPoint dst = circuitIntent.getDst(); 323 ConnectPoint dst = circuitIntent.getDst();
274 // Ignore if the intents don't have identical src and dst devices 324 // Ignore if the intents don't have identical src and dst devices
275 - if (!src.deviceId().equals(connIntent.getSrc().deviceId()) && 325 + if (!src.deviceId().equals(connIntent.getSrc().deviceId()) ||
276 !dst.deviceId().equals(connIntent.getDst().deviceId())) { 326 !dst.deviceId().equals(connIntent.getDst().deviceId())) {
277 continue; 327 continue;
278 } 328 }
...@@ -281,14 +331,68 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -281,14 +331,68 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
281 continue; 331 continue;
282 } 332 }
283 333
284 - if (isAvailable(connIntent.id())) { 334 + if (!isAvailable(connIntent.id())) {
285 - return connIntent; 335 + continue;
336 + }
337 +
338 + if (multiplexingSupported) {
339 + if (!isAvailableTributarySlots(connIntent, oduSignalType.tributarySlots())) {
340 + continue;
341 + }
286 } 342 }
343 +
344 + return connIntent;
287 } 345 }
288 346
289 return null; 347 return null;
290 } 348 }
291 349
350 + private boolean isAvailableTributarySlots(OpticalConnectivityIntent connIntent, int requestedTsNum) {
351 + Set<TributarySlot> common = findCommonTributarySlotsOnCps(connIntent.getSrc(), connIntent.getDst());
352 + if (common.isEmpty()) {
353 + log.debug("No available TributarySlots");
354 + return false;
355 + }
356 + if (common.size() < requestedTsNum) {
357 + log.debug("Not enough available TributarySlots={} < requestedTsNum={}", common.size(), requestedTsNum);
358 + return false;
359 + }
360 + return true;
361 + }
362 +
363 + private Set<TributarySlot> assignTributarySlots(OpticalCircuitIntent intent,
364 + Pair<ConnectPoint, ConnectPoint> ports) {
365 +
366 + OduSignalType oduSignalType = mappingCltSignalTypeToOduSignalType(intent.getSignalType());
367 + int requestedTsNum = oduSignalType.tributarySlots();
368 + Set<TributarySlot> commonTributarySlots = findCommonTributarySlotsOnCps(ports.getLeft(), ports.getRight());
369 + if (commonTributarySlots.isEmpty()) {
370 + return Collections.emptySet();
371 + }
372 + if (commonTributarySlots.size() < requestedTsNum) {
373 + return Collections.emptySet();
374 + }
375 +
376 + Set<TributarySlot> tributarySlots = commonTributarySlots.stream()
377 + .limit(requestedTsNum)
378 + .collect(Collectors.toSet());
379 +
380 + final List<ConnectPoint> portsList = ImmutableList.of(ports.getLeft(), ports.getRight());
381 + List<Resource> tributarySlotResources = portsList.stream()
382 + .flatMap(cp -> tributarySlots
383 + .stream()
384 + .map(ts-> Resources.discrete(cp.deviceId(), cp.port()).resource().child(ts)))
385 + .collect(Collectors.toList());
386 +
387 + List<ResourceAllocation> allocations = resourceService.allocate(intent.id(), tributarySlotResources);
388 + if (allocations.isEmpty()) {
389 + log.debug("Resource allocation for {} failed (resource request: {})",
390 + intent, tributarySlotResources);
391 + return Collections.emptySet();
392 + }
393 + return tributarySlots;
394 + }
395 +
292 private ConnectPoint staticPort(ConnectPoint connectPoint) { 396 private ConnectPoint staticPort(ConnectPoint connectPoint) {
293 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port()); 397 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
294 398
...@@ -306,7 +410,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -306,7 +410,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
306 return null; 410 return null;
307 } 411 }
308 412
309 - private OchPort findAvailableOchPort(ConnectPoint oduPort) { 413 + private OchPort findAvailableOchPort(ConnectPoint oduPort, OduSignalType ochPortSignalType) {
310 // First see if the port mappings are constrained 414 // First see if the port mappings are constrained
311 ConnectPoint ochCP = staticPort(oduPort); 415 ConnectPoint ochCP = staticPort(oduPort);
312 416
...@@ -323,6 +427,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -323,6 +427,7 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
323 if (isAvailable(intentId.orElse(null))) { 427 if (isAvailable(intentId.orElse(null))) {
324 return ochPort; 428 return ochPort;
325 } 429 }
430 + return null;
326 } 431 }
327 432
328 // No port constraints, so find any port that works 433 // No port constraints, so find any port that works
...@@ -332,6 +437,14 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -332,6 +437,14 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
332 if (!(port instanceof OchPort)) { 437 if (!(port instanceof OchPort)) {
333 continue; 438 continue;
334 } 439 }
440 + // This should be the first allocation on the OCH port
441 + if (!resourceService.isAvailable(Resources.discrete(oduPort.deviceId(), port.number()).resource())) {
442 + continue;
443 + }
444 + // OchPort is required to have the requested oduSignalType
445 + if (((OchPort) port).signalType() != ochPortSignalType) {
446 + continue;
447 + }
335 448
336 Optional<IntentId> intentId = 449 Optional<IntentId> intentId =
337 resourceService.getResourceAllocations(Resources.discrete(oduPort.deviceId(), port.number()).id()) 450 resourceService.getResourceAllocations(Resources.discrete(oduPort.deviceId(), port.number()).id())
...@@ -350,13 +463,34 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -350,13 +463,34 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
350 } 463 }
351 464
352 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) { 465 private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent) {
466 + Pair<OchPort, OchPort> ochPorts = null;
467 + // According to the OpticalCircuitIntent's signalType find OCH ports with available TributarySlots resources
468 + switch (intent.getSignalType()) {
469 + case CLT_1GBE:
470 + case CLT_10GBE:
471 + // First search for OCH ports with OduSignalType of ODU2. If not found - search for those with ODU4
472 + ochPorts = findPorts(intent, OduSignalType.ODU2);
473 + if (ochPorts == null) {
474 + ochPorts = findPorts(intent, OduSignalType.ODU4);
475 + }
476 + break;
477 + case CLT_100GBE:
478 + ochPorts = findPorts(intent, OduSignalType.ODU4);
479 + break;
480 + case CLT_40GBE:
481 + default:
482 + break;
483 + }
484 + return ochPorts;
485 + }
353 486
354 - OchPort srcPort = findAvailableOchPort(intent.getSrc()); 487 + private Pair<OchPort, OchPort> findPorts(OpticalCircuitIntent intent, OduSignalType ochPortSignalType) {
488 + OchPort srcPort = findAvailableOchPort(intent.getSrc(), ochPortSignalType);
355 if (srcPort == null) { 489 if (srcPort == null) {
356 return null; 490 return null;
357 } 491 }
358 492
359 - OchPort dstPort = findAvailableOchPort(intent.getDst()); 493 + OchPort dstPort = findAvailableOchPort(intent.getDst(), ochPortSignalType);
360 if (dstPort == null) { 494 if (dstPort == null) {
361 return null; 495 return null;
362 } 496 }
...@@ -369,18 +503,46 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -369,18 +503,46 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
369 * 503 *
370 * @param src source port 504 * @param src source port
371 * @param dst destination port 505 * @param dst destination port
506 + * @param priority
507 + * @param slots Set of TributarySlots
372 * @return flow rules 508 * @return flow rules
373 */ 509 */
374 - private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst, int priority) { 510 + private FlowRule connectPorts(ConnectPoint src, ConnectPoint dst, int priority, Set<TributarySlot> slots) {
375 checkArgument(src.deviceId().equals(dst.deviceId())); 511 checkArgument(src.deviceId().equals(dst.deviceId()));
376 512
377 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); 513 TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
378 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); 514 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
379 515
380 selectorBuilder.matchInPort(src.port()); 516 selectorBuilder.matchInPort(src.port());
381 - //selectorBuilder.add(Criteria.matchCltSignalType) 517 + if (!slots.isEmpty()) {
518 + Port srcPort = deviceService.getPort(src.deviceId(), src.port());
519 + Port dstPort = deviceService.getPort(dst.deviceId(), dst.port());
520 + OduSignalType oduCltPortOduSignalType;
521 + OduSignalType ochPortOduSignalType;
522 +
523 + if (srcPort instanceof OduCltPort) {
524 + oduCltPortOduSignalType = mappingCltSignalTypeToOduSignalType(((OduCltPort) srcPort).signalType());
525 + ochPortOduSignalType = ((OchPort) dstPort).signalType();
526 +
527 + selectorBuilder.add(Criteria.matchOduSignalType(oduCltPortOduSignalType));
528 + // use Instruction of OduSignalId only in case of ODU Multiplexing
529 + if (oduCltPortOduSignalType != ochPortOduSignalType) {
530 + OduSignalId oduSignalId = buildOduSignalId(ochPortOduSignalType, slots);
531 + treatmentBuilder.add(Instructions.modL1OduSignalId(oduSignalId));
532 + }
533 + } else { // srcPort is OchPort
534 + oduCltPortOduSignalType = mappingCltSignalTypeToOduSignalType(((OduCltPort) dstPort).signalType());
535 + ochPortOduSignalType = ((OchPort) srcPort).signalType();
536 +
537 + selectorBuilder.add(Criteria.matchOduSignalType(oduCltPortOduSignalType));
538 + // use Criteria of OduSignalId only in case of ODU Multiplexing
539 + if (oduCltPortOduSignalType != ochPortOduSignalType) {
540 + OduSignalId oduSignalId = buildOduSignalId(ochPortOduSignalType, slots);
541 + selectorBuilder.add(Criteria.matchOduSignalId(oduSignalId));
542 + }
543 + }
544 + }
382 treatmentBuilder.setOutput(dst.port()); 545 treatmentBuilder.setOutput(dst.port());
383 - //treatmentBuilder.add(Instructions.modL1OduSignalType)
384 546
385 FlowRule flowRule = DefaultFlowRule.builder() 547 FlowRule flowRule = DefaultFlowRule.builder()
386 .forDevice(src.deviceId()) 548 .forDevice(src.deviceId())
...@@ -393,4 +555,98 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu ...@@ -393,4 +555,98 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu
393 555
394 return flowRule; 556 return flowRule;
395 } 557 }
558 +
559 + private OduSignalId buildOduSignalId(OduSignalType ochPortSignalType, Set<TributarySlot> slots) {
560 + int tributaryPortNumber = findFirstTributarySlotIndex(slots);
561 + int tributarySlotLen = ochPortSignalType.tributarySlots();
562 + byte[] tributarySlotBitmap = new byte[OduSignalId.TRIBUTARY_SLOT_BITMAP_SIZE];
563 +
564 + slots.forEach(ts -> tributarySlotBitmap[(byte) (ts.index() - 1) / 8] |= 0x1 << ((ts.index() - 1) % 8));
565 + return OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap);
566 + }
567 +
568 + private int findFirstTributarySlotIndex(Set<TributarySlot> tributarySlots) {
569 + return (int) tributarySlots.stream().findFirst().get().index();
570 + }
571 +
572 + private boolean isTributarySlotBehaviourSupported(DeviceId deviceId) {
573 + Driver driver = driverService.getDriver(deviceId);
574 + return (driver != null && driver.hasBehaviour(TributarySlotQuery.class));
575 + }
576 +
577 + private boolean isMultiplexingSupported(OpticalCircuitIntent intent) {
578 + ConnectPoint src = intent.getSrc();
579 + ConnectPoint dst = intent.getDst();
580 +
581 + if (!isTributarySlotBehaviourSupported(src.deviceId()) ||
582 + !isTributarySlotBehaviourSupported(dst.deviceId())) {
583 + return false;
584 + }
585 +
586 + ConnectPoint srcStaticPort = staticPort(src);
587 + if (srcStaticPort != null) {
588 + return false;
589 + }
590 + ConnectPoint dstStaticPort = staticPort(dst);
591 + if (dstStaticPort != null) {
592 + return false;
593 + }
594 +
595 + return true;
596 + }
597 +
598 + /**
599 + * Maps from Intent's OduClt SignalType to OduSignalType.
600 + *
601 + * @param cltSignalType OduClt port signal type
602 + * @return OduSignalType the result of mapping CltSignalType to OduSignalType
603 + */
604 + OduSignalType mappingCltSignalTypeToOduSignalType(CltSignalType cltSignalType) {
605 + OduSignalType oduSignalType = OduSignalType.ODU0;
606 + switch (cltSignalType) {
607 + case CLT_1GBE:
608 + oduSignalType = OduSignalType.ODU0;
609 + break;
610 + case CLT_10GBE:
611 + oduSignalType = OduSignalType.ODU2;
612 + break;
613 + case CLT_40GBE:
614 + oduSignalType = OduSignalType.ODU3;
615 + break;
616 + case CLT_100GBE:
617 + oduSignalType = OduSignalType.ODU4;
618 + break;
619 + default:
620 + log.error("Unsupported CltSignalType {}", cltSignalType);
621 + break;
622 + }
623 + return oduSignalType;
624 + }
625 +
626 + /**
627 + * Finds the common TributarySlots available on the two connect points.
628 + *
629 + * @param srcCp source connect point
630 + * @param dstCp dest connect point
631 + * @return set of common TributarySlots on both connect points
632 + */
633 + Set<TributarySlot> findCommonTributarySlotsOnCps(ConnectPoint srcCp, ConnectPoint dstCp) {
634 + Set<TributarySlot> forward = findTributarySlotsOnCp(srcCp);
635 + Set<TributarySlot> backward = findTributarySlotsOnCp(dstCp);
636 + return Sets.intersection(forward, backward);
637 + }
638 +
639 + /**
640 + * Finds the TributarySlots available on the connect point.
641 + *
642 + * @param cp connect point
643 + * @return set of TributarySlots available on the connect point
644 + */
645 + Set<TributarySlot> findTributarySlotsOnCp(ConnectPoint cp) {
646 + return resourceService.getAvailableResources(Resources.discrete(cp.deviceId(), cp.port()).id())
647 + .stream()
648 + .filter(x -> x.last() instanceof TributarySlot)
649 + .map(x -> (TributarySlot) x.last())
650 + .collect(Collectors.toSet());
651 + }
396 } 652 }
......
...@@ -108,6 +108,11 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical ...@@ -108,6 +108,11 @@ public class OpticalConnectivityIntentCompiler implements IntentCompiler<Optical
108 108
109 log.debug("Compiling optical connectivity intent between {} and {}", src, dst); 109 log.debug("Compiling optical connectivity intent between {} and {}", src, dst);
110 110
111 + // Release of intent resources here is only a temporary solution for handling the
112 + // case of recompiling due to intent restoration (when intent state is FAILED).
113 + // TODO: try to release intent resources in IntentManager.
114 + resourceService.release(intent.id());
115 +
111 // Reserve OCh ports 116 // Reserve OCh ports
112 Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource(); 117 Resource srcPortResource = Resources.discrete(src.deviceId(), src.port()).resource();
113 Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource(); 118 Resource dstPortResource = Resources.discrete(dst.deviceId(), dst.port()).resource();
......