blob: 9a3f30a4f868a9196734a3e713f9c214ee26806e [file] [log] [blame]
Jimmy Yanda878fc2016-09-02 16:32:01 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jimmy Yanda878fc2016-09-02 16:32:01 -07003 *
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.roadm;
17
MaoLu2846b112017-05-15 17:18:55 -070018import com.google.common.collect.ImmutableMap;
Jimmy Yanda878fc2016-09-02 16:32:01 -070019import com.google.common.collect.Range;
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -070020import org.onlab.util.Frequency;
Jimmy Yanda878fc2016-09-02 16:32:01 -070021import org.onosproject.core.ApplicationId;
22import org.onosproject.core.CoreService;
23import org.onosproject.net.ChannelSpacing;
MaoLu937cf422017-03-03 23:31:46 -080024import org.onosproject.net.ConnectPoint;
Jimmy Yanda878fc2016-09-02 16:32:01 -070025import org.onosproject.net.Device;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.Direction;
Andrea Campanellabdeeda12019-08-02 16:12:05 +020028import org.onosproject.net.ModulationScheme;
Jimmy Yanda878fc2016-09-02 16:32:01 -070029import org.onosproject.net.OchSignal;
Jimmy Yanda878fc2016-09-02 16:32:01 -070030import org.onosproject.net.Port;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.behaviour.LambdaQuery;
Andrea Campanellabdeeda12019-08-02 16:12:05 +020033import org.onosproject.net.behaviour.ModulationConfig;
Jimmy Yanda878fc2016-09-02 16:32:01 -070034import org.onosproject.net.behaviour.PowerConfig;
MaoLu937cf422017-03-03 23:31:46 -080035import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070036import org.onosproject.net.behaviour.protection.ProtectionConfigBehaviour;
MaoLu937cf422017-03-03 23:31:46 -080037import org.onosproject.net.behaviour.protection.TransportEndpointState;
Jimmy Yanda878fc2016-09-02 16:32:01 -070038import org.onosproject.net.device.DeviceEvent;
39import org.onosproject.net.device.DeviceListener;
40import org.onosproject.net.device.DeviceService;
41import org.onosproject.net.flow.DefaultFlowRule;
42import org.onosproject.net.flow.DefaultTrafficSelector;
43import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.FlowEntry;
45import org.onosproject.net.flow.FlowId;
46import org.onosproject.net.flow.FlowRule;
47import org.onosproject.net.flow.FlowRuleService;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
50import org.onosproject.net.flow.criteria.Criteria;
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -070051import org.onosproject.net.flow.instructions.Instruction;
Jimmy Yanda878fc2016-09-02 16:32:01 -070052import org.onosproject.net.flow.instructions.Instructions;
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -070053import org.onosproject.net.flow.instructions.L0ModificationInstruction;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070054import org.osgi.service.component.annotations.Activate;
55import org.osgi.service.component.annotations.Component;
56import org.osgi.service.component.annotations.Deactivate;
57import org.osgi.service.component.annotations.Reference;
58import org.osgi.service.component.annotations.ReferenceCardinality;
Jimmy Yanda878fc2016-09-02 16:32:01 -070059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
62import java.util.Collections;
63import java.util.List;
MaoLu937cf422017-03-03 23:31:46 -080064import java.util.Map;
Jimmy Yanda878fc2016-09-02 16:32:01 -070065import java.util.Optional;
66import java.util.Set;
MaoLu937cf422017-03-03 23:31:46 -080067import java.util.concurrent.ExecutionException;
Jimmy Yanda878fc2016-09-02 16:32:01 -070068import java.util.concurrent.TimeUnit;
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -070069import java.util.stream.StreamSupport;
Jimmy Yanda878fc2016-09-02 16:32:01 -070070
71import static com.google.common.base.Preconditions.checkNotNull;
MaoLu2846b112017-05-15 17:18:55 -070072import static org.onosproject.net.optical.OpticalAnnotations.INPUT_PORT_STATUS;
73import static org.onosproject.roadm.RoadmUtil.OPS_OPT_AUTO;
74import static org.onosproject.roadm.RoadmUtil.OPS_OPT_FORCE;
75import static org.onosproject.roadm.RoadmUtil.OPS_OPT_MANUAL;
Jimmy Yanda878fc2016-09-02 16:32:01 -070076
77/**
78 * Application for monitoring and configuring ROADM devices.
79 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070080@Component(immediate = true, service = RoadmService.class)
Jimmy Yanda878fc2016-09-02 16:32:01 -070081public class RoadmManager implements RoadmService {
82
83 private static final String APP_NAME = "org.onosproject.roadm";
84 private ApplicationId appId;
85
86 private final Logger log = LoggerFactory.getLogger(getClass());
87
88 private DeviceListener deviceListener = new InternalDeviceListener();
89
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070091 protected RoadmStore roadmStore;
92
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070094 protected CoreService coreService;
95
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070097 protected DeviceService deviceService;
98
Ray Milkeyd84f89b2018-08-17 14:54:17 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -0700100 protected FlowRuleService flowRuleService;
101
102 @Activate
103 protected void activate() {
104 appId = coreService.registerApplication(APP_NAME);
105 deviceService.addListener(deviceListener);
106 initDevices();
107
108 log.info("Started");
109 }
110
111 @Deactivate
112 protected void deactivate() {
113 deviceService.removeListener(deviceListener);
114
115 log.info("Stopped");
116 }
117
MaoLu2846b112017-05-15 17:18:55 -0700118 @Deprecated
MaoLu937cf422017-03-03 23:31:46 -0800119 @Override
120 public void setProtectionSwitchWorkingPath(DeviceId deviceId, int index) {
121 checkNotNull(deviceId);
122 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
123 if (behaviour == null) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700124 return;
125 }
MaoLu937cf422017-03-03 23:31:46 -0800126 Map<ConnectPoint, ProtectedTransportEndpointState> map = getProtectionSwitchStates(behaviour);
127 if (map == null) {
128 log.warn("Failed to get protected transport endpoint state in device {}", deviceId);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700129 return;
130 }
MaoLu937cf422017-03-03 23:31:46 -0800131 if (map.isEmpty()) {
132 log.warn("No protected transport endpoint state found in device {}", deviceId);
133 return;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700134 }
Ray Milkey4f7e3632019-02-19 15:35:20 -0800135 behaviour.switchToManual(map.keySet().toArray(new ConnectPoint[0])[0], index);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700136 }
137
MaoLu2846b112017-05-15 17:18:55 -0700138 @Deprecated
MaoLu937cf422017-03-03 23:31:46 -0800139 @Override
140 public String getProtectionSwitchPortState(DeviceId deviceId, PortNumber portNumber) {
141 checkNotNull(deviceId);
142 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
143 if (behaviour == null) {
144 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700145 }
MaoLu937cf422017-03-03 23:31:46 -0800146 Map<ConnectPoint, ProtectedTransportEndpointState> map = getProtectionSwitchStates(behaviour);
147 if (map == null) {
148 log.warn("Failed to get protected transport endpoint state in device {}", deviceId);
149 return null;
150 }
151 for (ProtectedTransportEndpointState state : map.values()) {
152 for (TransportEndpointState element : state.pathStates()) {
153 if (element.description().output().connectPoint().port().equals(portNumber)) {
MaoLu2846b112017-05-15 17:18:55 -0700154 return element.attributes().get(INPUT_PORT_STATUS);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700155 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700156 }
157 }
MaoLudd5a00b2017-03-14 11:19:48 -0700158 // Do not need warning here for port polling.
159 log.debug("Unable to get port status, device: {}, port: {}", deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800160 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700161 }
162
163 @Override
MaoLu2846b112017-05-15 17:18:55 -0700164 public void configProtectionSwitch(DeviceId deviceId, String operation, ConnectPoint identifier, int index) {
165 checkNotNull(deviceId);
166 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
167 if (behaviour == null) {
168 return;
169 }
170 // automatic operation
171 if (OPS_OPT_AUTO.equals(operation)) {
172 behaviour.switchToAutomatic(identifier);
173 return;
174 }
175 // force or manual operation
176 if (OPS_OPT_MANUAL.equals(operation)) {
177 behaviour.switchToManual(identifier, index);
178 } else if (OPS_OPT_FORCE.equals(operation)) {
179 behaviour.switchToForce(identifier, index);
180 }
181 }
182
183 @Override
184 public Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(DeviceId deviceId) {
185 checkNotNull(deviceId);
186 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
187 if (behaviour == null) {
188 return ImmutableMap.of();
189 }
190 return getProtectionSwitchStates(behaviour);
191 }
192
193
194 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200195 public void setTargetPortPower(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700196 checkNotNull(deviceId);
197 checkNotNull(portNumber);
198 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
199 if (powerConfig != null) {
200 roadmStore.setTargetPower(deviceId, portNumber, power);
201 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
202 } else {
203 log.warn("Unable to set target port power for device {}", deviceId);
204 }
205 }
206
207 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200208 public Double getTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700209 checkNotNull(deviceId);
210 checkNotNull(portNumber);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700211 // Request target port power when it doesn't exist. Inactive updating mode.
Andrea Campanelladadf6402019-08-07 15:24:11 +0200212 Double power = roadmStore.getTargetPower(deviceId, portNumber);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700213 if (power == null) {
214 return syncTargetPortPower(deviceId, portNumber);
215 }
216 return power;
217 }
218
219 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200220 public Double syncTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700221 checkNotNull(deviceId);
222 checkNotNull(portNumber);
223 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
224 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200225 Optional<Double> pl = powerConfig.getTargetPower(portNumber, Direction.ALL);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700226 if (pl.isPresent()) {
227 roadmStore.setTargetPower(deviceId, portNumber, pl.get());
228 return pl.get();
229 } else {
230 roadmStore.removeTargetPower(deviceId, portNumber);
231 }
232 }
233 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700234 }
235
236 @Override
237 public void setAttenuation(DeviceId deviceId, PortNumber portNumber,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200238 OchSignal ochSignal, double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700239 checkNotNull(deviceId);
240 checkNotNull(portNumber);
241 checkNotNull(ochSignal);
242 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
243 if (powerConfig != null) {
244 powerConfig.setTargetPower(portNumber, ochSignal, attenuation);
245 } else {
246 log.warn("Cannot set attenuation for channel index {} on device {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200247 ochSignal.spacingMultiplier(), deviceId);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700248 }
249 }
250
251 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200252 public Double getAttenuation(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700253 checkNotNull(deviceId);
254 checkNotNull(portNumber);
255 checkNotNull(ochSignal);
256 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
257 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200258 Optional<Double> attenuation = powerConfig.getTargetPower(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700259 if (attenuation.isPresent()) {
260 return attenuation.get();
261 }
262 }
263 return null;
264 }
265
266 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200267 public Double getCurrentPortPower(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700268 checkNotNull(deviceId);
269 checkNotNull(portNumber);
270 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
271 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200272 Optional<Double> currentPower = powerConfig.currentPower(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700273 if (currentPower.isPresent()) {
274 return currentPower.get();
275 }
276 }
277 return null;
278 }
279
280 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200281 public Double getCurrentChannelPower(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700282 checkNotNull(deviceId);
283 checkNotNull(portNumber);
284 checkNotNull(ochSignal);
285 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
286 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200287 Optional<Double> currentPower = powerConfig.currentPower(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700288 if (currentPower.isPresent()) {
289 return currentPower.get();
290 }
291 }
292 return null;
293 }
294
295 @Override
296 public Set<OchSignal> queryLambdas(DeviceId deviceId, PortNumber portNumber) {
297 checkNotNull(deviceId);
298 checkNotNull(portNumber);
299 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
300 if (lambdaQuery != null) {
301 return lambdaQuery.queryLambdas(portNumber);
302 }
303 return Collections.emptySet();
304 }
305
306 @Override
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200307 public ModulationScheme getModulation(DeviceId deviceId, PortNumber portNumber) {
308 checkNotNull(deviceId);
309 checkNotNull(portNumber);
310 Device device = deviceService.getDevice(deviceId);
311 Direction component = Direction.ALL;
312 if (device.is(ModulationConfig.class)) {
313 ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
314 Optional<ModulationScheme> scheme = modulationConfig.getModulationScheme(portNumber, component);
315 if (scheme.isPresent()) {
316 return scheme.get();
317 }
318 }
319 return null;
320 }
321
322 @Override
323 public void setModulation(DeviceId deviceId, PortNumber portNumber, String modulation) {
324 checkNotNull(deviceId);
325 checkNotNull(portNumber);
326 Device device = deviceService.getDevice(deviceId);
327 Direction component = Direction.ALL;
328 if (device.is(ModulationConfig.class)) {
329 ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
330 long bitRate = 0;
Andrea Campanella1ac57982019-08-30 11:08:57 -0700331 if (modulation.equalsIgnoreCase(ModulationScheme.DP_QPSK.name())) {
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200332 bitRate = 100;
333 } else {
334 bitRate = 200;
335 }
336 modulationConfig.setModulationScheme(portNumber, component, bitRate);
337 }
338
339 }
340
341 @Override
Jimmy Yanda878fc2016-09-02 16:32:01 -0700342 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200343 int timeout, PortNumber inPort, PortNumber outPort, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700344 checkNotNull(deviceId);
345 checkNotNull(inPort);
346 checkNotNull(outPort);
347
MaoLu937cf422017-03-03 23:31:46 -0800348 TrafficSelector selector = DefaultTrafficSelector.builder()
349 .add(Criteria.matchInPort(inPort))
MaoLu937cf422017-03-03 23:31:46 -0800350 .build();
351 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
alessioc6f054b2019-07-22 11:05:07 +0200352 .add(Instructions.modL0Lambda(ochSignal))
MaoLu937cf422017-03-03 23:31:46 -0800353 .add(Instructions.createOutput(outPort))
354 .build();
355
356 FlowRule.Builder flowBuilder = DefaultFlowRule.builder()
357 .forDevice(deviceId)
358 .fromApp(appId)
359 .withPriority(priority)
360 .withSelector(selector)
361 .withTreatment(treatment);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700362 if (isPermanent) {
363 flowBuilder.makePermanent();
364 } else {
365 flowBuilder.makeTemporary(timeout);
366 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700367
368 FlowRule flowRule = flowBuilder.build();
369 flowRuleService.applyFlowRules(flowRule);
370
371 log.info("Created connection from input port {} to output port {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200372 inPort.toLong(), outPort.toLong());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700373
374 return flowRule.id();
375 }
376
377 @Override
378 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -0700379 int timeout, PortNumber inPort, PortNumber outPort,
380 OchSignal ochSignal, Double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700381 checkNotNull(deviceId);
382 checkNotNull(inPort);
383 checkNotNull(outPort);
MaoLu937cf422017-03-03 23:31:46 -0800384 FlowId flowId = createConnection(deviceId, priority, isPermanent, timeout, inPort, outPort, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700385 delayedSetAttenuation(deviceId, outPort, ochSignal, attenuation);
386 return flowId;
387 }
388
Jimmy Yanda878fc2016-09-02 16:32:01 -0700389 @Override
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -0700390 public Frequency getWavelength(DeviceId deviceId, PortNumber portNumber) {
391 checkNotNull(deviceId);
392 checkNotNull(portNumber);
393 Optional<FlowEntry> optFlow = StreamSupport
394 .stream(flowRuleService.getFlowEntries(deviceId).spliterator(), false)
395 .filter(flow -> {
396 return flow.treatment().allInstructions().stream().filter(instr -> {
397 if (instr.type().equals(Instruction.Type.OUTPUT)) {
398 return ((Instructions.OutputInstruction) instr).port().equals(portNumber);
399 } else if (instr.type().equals(Instruction.Type.L0MODIFICATION)) {
400 return ((L0ModificationInstruction) instr).subtype()
401 .equals(L0ModificationInstruction.L0SubType.OCH);
402 }
403 return false;
404 }).count() == 2;
405 }).findFirst();
406 if (optFlow.isPresent()) {
407 Optional<Instruction> instruction = optFlow.get().treatment().allInstructions().stream().filter(instr -> {
408 if (instr.type().equals(Instruction.Type.L0MODIFICATION)) {
409 return ((L0ModificationInstruction) instr).subtype()
410 .equals(L0ModificationInstruction.L0SubType.OCH);
411 }
412 return false;
413 }).findAny();
414 if (instruction.isPresent()) {
415 return ((L0ModificationInstruction.ModOchSignalInstruction) instruction.get()).lambda()
416 .centralFrequency();
417 }
418 }
419 return null;
420 }
421
422 @Override
Jimmy Yanda878fc2016-09-02 16:32:01 -0700423 public void removeConnection(DeviceId deviceId, FlowId flowId) {
424 checkNotNull(deviceId);
425 checkNotNull(flowId);
426 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
427 if (entry.id().equals(flowId)) {
428 flowRuleService.removeFlowRules(entry);
429 log.info("Deleted connection {}", entry.id());
430 break;
431 }
432 }
433 }
434
435 @Override
436 public boolean hasPortTargetPower(DeviceId deviceId, PortNumber portNumber) {
437 checkNotNull(deviceId);
438 checkNotNull(portNumber);
439 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
440 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200441 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700442 return range.isPresent();
443 }
444 return false;
445 }
446
447 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200448 public boolean portTargetPowerInRange(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700449 checkNotNull(deviceId);
450 checkNotNull(portNumber);
451 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
452 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200453 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700454 return range.isPresent() && range.get().contains(power);
455 }
456 return false;
457 }
458
459 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200460 public boolean attenuationInRange(DeviceId deviceId, PortNumber outPort, double att) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700461 checkNotNull(deviceId);
462 checkNotNull(outPort);
463 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
464 if (powerConfig != null) {
465 OchSignal stubOch = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 0);
Andrea Campanelladadf6402019-08-07 15:24:11 +0200466 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(outPort, stubOch);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700467 return range.isPresent() && range.get().contains(att);
468 }
469 return false;
470 }
471
472 @Override
473 public boolean validInputPort(DeviceId deviceId, PortNumber portNumber) {
474 checkNotNull(deviceId);
475 checkNotNull(portNumber);
476 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
477 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200478 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700479 return range.isPresent();
480 }
481 return false;
482 }
483
484 @Override
485 public boolean validOutputPort(DeviceId deviceId, PortNumber portNumber) {
486 return hasPortTargetPower(deviceId, portNumber);
487 }
488
489 @Override
MaoLu937cf422017-03-03 23:31:46 -0800490 public boolean validChannel(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700491 checkNotNull(deviceId);
492 checkNotNull(portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800493 checkNotNull(ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700494 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
495 if (lambdaQuery != null) {
496 Set<OchSignal> channels = lambdaQuery.queryLambdas(portNumber);
497 return channels.contains(ochSignal);
498 }
499 return false;
500 }
501
502 @Override
503 public boolean channelAvailable(DeviceId deviceId, OchSignal ochSignal) {
504 checkNotNull(deviceId);
505 checkNotNull(ochSignal);
506 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
507 if (ChannelData.fromFlow(entry).ochSignal().equals(ochSignal)) {
508 return false;
509 }
510 }
511 return true;
512 }
513
514 @Override
MaoLu937cf422017-03-03 23:31:46 -0800515 public boolean validConnection(DeviceId deviceId, PortNumber inPort, PortNumber outPort) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700516 checkNotNull(deviceId);
517 checkNotNull(inPort);
518 checkNotNull(outPort);
519 return validInputPort(deviceId, inPort) && validOutputPort(deviceId, outPort);
520 }
521
522 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200523 public Range<Double> targetPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700524 checkNotNull(deviceId);
525 checkNotNull(portNumber);
526 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
527 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200528 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700529 if (range.isPresent()) {
530 return range.get();
531 }
532 }
533 return null;
534 }
535
536 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200537 public Range<Double> attenuationRange(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700538 checkNotNull(deviceId);
539 checkNotNull(portNumber);
540 checkNotNull(ochSignal);
541 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
542 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200543 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700544 if (range.isPresent()) {
545 return range.get();
546 }
547 }
548 return null;
549 }
550
551 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200552 public Range<Double> inputPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700553 checkNotNull(deviceId);
554 checkNotNull(portNumber);
555 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
556 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200557 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700558 if (range.isPresent()) {
559 return range.get();
560 }
561 }
562 return null;
563 }
564
MaoLu937cf422017-03-03 23:31:46 -0800565 private PowerConfig<Object> getPowerConfig(DeviceId deviceId) {
566 Device device = deviceService.getDevice(deviceId);
567 if (device != null && device.is(PowerConfig.class)) {
568 return device.as(PowerConfig.class);
569 }
MaoLudd5a00b2017-03-14 11:19:48 -0700570 // Do not need warning here for port polling.
571 log.debug("Unable to load PowerConfig for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800572 return null;
573 }
574
575 private LambdaQuery getLambdaQuery(DeviceId deviceId) {
576 Device device = deviceService.getDevice(deviceId);
577 if (device != null && device.is(LambdaQuery.class)) {
578 return device.as(LambdaQuery.class);
579 }
MaoLudd5a00b2017-03-14 11:19:48 -0700580 // Do not need warning here for port polling.
581 log.debug("Unable to load LambdaQuery for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800582 return null;
583 }
584
585 private ProtectionConfigBehaviour getProtectionConfig(DeviceId deviceId) {
586 Device device = deviceService.getDevice(deviceId);
587 if (device != null && device.is(ProtectionConfigBehaviour.class)) {
588 return device.as(ProtectionConfigBehaviour.class);
589 }
MaoLudd5a00b2017-03-14 11:19:48 -0700590 // Do not need warning here for port polling.
591 log.debug("Unable to load ProtectionConfigBehaviour for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800592 return null;
593 }
594
595 // Initialize all devices
596 private void initDevices() {
597 for (Device device : deviceService.getDevices(Device.Type.ROADM)) {
598 initDevice(device.id());
599 //FIXME
600 // As roadm application is a optional tool for now.
601 // The target power initialization will be enhanced later,
602 // hopefully using an formal optical subsystem.
603 // setAllInitialTargetPortPowers(device.id());
604 }
605 }
606
607 // Initialize RoadmStore for a device to support target power
608 private void initDevice(DeviceId deviceId) {
609 if (!roadmStore.deviceAvailable(deviceId)) {
610 roadmStore.addDevice(deviceId);
611 }
612 log.info("Initialized device {}", deviceId);
613 }
614
615 // Sets the target port powers for a port on a device
616 // Attempts to read target powers from store. If no value is found then
617 // default value is used instead.
618 private void setInitialTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
619 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
620 if (powerConfig == null) {
621 log.warn("Unable to set default initial powers for port {} on device {}", portNumber, deviceId);
622 return;
623 }
624
Andrea Campanelladadf6402019-08-07 15:24:11 +0200625 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800626 if (!range.isPresent()) {
627 log.warn("No target power range found for port {} on device {}", portNumber, deviceId);
628 return;
629 }
630
Andrea Campanelladadf6402019-08-07 15:24:11 +0200631 Double power = roadmStore.getTargetPower(deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800632 if (power == null) {
633 // Set default to middle of the range
634 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
635 roadmStore.setTargetPower(deviceId, portNumber, power);
636 }
637 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
638 }
639
640 // Sets the target port powers for each each port on a device
641 // Attempts to read target powers from store. If no value is found then
642 // default value is used instead
643 private void setAllInitialTargetPortPowers(DeviceId deviceId) {
644 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
645 if (powerConfig == null) {
646 log.warn("Unable to set default initial powers for device {}", deviceId);
647 return;
648 }
649
650 List<Port> ports = deviceService.getPorts(deviceId);
651 for (Port port : ports) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200652 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(port.number(), Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800653 if (range.isPresent()) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200654 Double power = roadmStore.getTargetPower(deviceId, port.number());
MaoLu937cf422017-03-03 23:31:46 -0800655 if (power == null) {
656 // Set default to middle of the range
657 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
658 roadmStore.setTargetPower(deviceId, port.number(), power);
659 }
660 powerConfig.setTargetPower(port.number(), Direction.ALL, power);
661 } else {
662 log.warn("No target power range found for port {} on device {}", port.number(), deviceId);
663 }
664 }
665 }
666
667 // Delay the call to setTargetPower because the flow may not be in the store yet
alessio1bf2a632019-06-04 15:47:39 +0200668 // Tested with Lumentum ROADM-20 1 seconds was not enough, increased to 5 seconds
MaoLu937cf422017-03-03 23:31:46 -0800669 private void delayedSetAttenuation(DeviceId deviceId, PortNumber outPort,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200670 OchSignal ochSignal, Double attenuation) {
MaoLu937cf422017-03-03 23:31:46 -0800671 Runnable setAtt = () -> {
672 try {
alessio1bf2a632019-06-04 15:47:39 +0200673 TimeUnit.SECONDS.sleep(5);
MaoLu937cf422017-03-03 23:31:46 -0800674 } catch (InterruptedException e) {
675 log.warn("Thread interrupted. Setting attenuation early.");
MaoLu2846b112017-05-15 17:18:55 -0700676 Thread.currentThread().interrupt();
MaoLu937cf422017-03-03 23:31:46 -0800677 }
678 setAttenuation(deviceId, outPort, ochSignal, attenuation);
679 };
680 new Thread(setAtt).start();
681 }
682
683 // get protection endpoint states
684 private Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(
685 ProtectionConfigBehaviour behaviour) {
MaoLu937cf422017-03-03 23:31:46 -0800686 Map<ConnectPoint, ProtectedTransportEndpointState> map;
687 try {
MaoLu2846b112017-05-15 17:18:55 -0700688 map = behaviour.getProtectionEndpointStates().get();
MaoLu937cf422017-03-03 23:31:46 -0800689 } catch (InterruptedException e1) {
690 log.error("Interrupted.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700691 Thread.currentThread().interrupt();
692 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800693 } catch (ExecutionException e1) {
694 log.error("Exception caught.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700695 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800696 }
697 return map;
698 }
699
Jimmy Yanda878fc2016-09-02 16:32:01 -0700700 // Listens to device events.
701 private class InternalDeviceListener implements DeviceListener {
702 @Override
703 public void event(DeviceEvent deviceEvent) {
704 Device device = deviceEvent.subject();
705
706 switch (deviceEvent.type()) {
707 case DEVICE_ADDED:
708 case DEVICE_UPDATED:
709 initDevice(device.id());
710 break;
711 case PORT_ADDED:
712 case PORT_UPDATED:
MaoLu937cf422017-03-03 23:31:46 -0800713 //FIXME
714 // As roadm application is a optional tool for now.
715 // The target power initialization will be enhanced later,
716 // hopefully using an formal optical subsystem.
717 // setInitialTargetPortPower(device.id(), deviceEvent.port().number());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700718 break;
719 default:
720 break;
721
722 }
723 }
724 }
725}