blob: d6812ba34df80fc7fe263ce0d76e344b1af3eff4 [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 Campanella7ebfe322019-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;
30import org.onosproject.net.OchSignalType;
31import org.onosproject.net.Port;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.behaviour.LambdaQuery;
Andrea Campanellabdeeda12019-08-02 16:12:05 +020034import org.onosproject.net.behaviour.ModulationConfig;
Jimmy Yanda878fc2016-09-02 16:32:01 -070035import org.onosproject.net.behaviour.PowerConfig;
MaoLu937cf422017-03-03 23:31:46 -080036import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070037import org.onosproject.net.behaviour.protection.ProtectionConfigBehaviour;
MaoLu937cf422017-03-03 23:31:46 -080038import org.onosproject.net.behaviour.protection.TransportEndpointState;
Jimmy Yanda878fc2016-09-02 16:32:01 -070039import org.onosproject.net.device.DeviceEvent;
40import org.onosproject.net.device.DeviceListener;
41import org.onosproject.net.device.DeviceService;
42import org.onosproject.net.flow.DefaultFlowRule;
43import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.FlowEntry;
46import org.onosproject.net.flow.FlowId;
47import org.onosproject.net.flow.FlowRule;
48import org.onosproject.net.flow.FlowRuleService;
49import org.onosproject.net.flow.TrafficSelector;
50import org.onosproject.net.flow.TrafficTreatment;
51import org.onosproject.net.flow.criteria.Criteria;
Andrea Campanella7ebfe322019-08-29 11:46:57 -070052import org.onosproject.net.flow.instructions.Instruction;
Jimmy Yanda878fc2016-09-02 16:32:01 -070053import org.onosproject.net.flow.instructions.Instructions;
Andrea Campanella7ebfe322019-08-29 11:46:57 -070054import org.onosproject.net.flow.instructions.L0ModificationInstruction;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055import org.osgi.service.component.annotations.Activate;
56import org.osgi.service.component.annotations.Component;
57import org.osgi.service.component.annotations.Deactivate;
58import org.osgi.service.component.annotations.Reference;
59import org.osgi.service.component.annotations.ReferenceCardinality;
Jimmy Yanda878fc2016-09-02 16:32:01 -070060import org.slf4j.Logger;
61import org.slf4j.LoggerFactory;
62
63import java.util.Collections;
64import java.util.List;
MaoLu937cf422017-03-03 23:31:46 -080065import java.util.Map;
Jimmy Yanda878fc2016-09-02 16:32:01 -070066import java.util.Optional;
67import java.util.Set;
MaoLu937cf422017-03-03 23:31:46 -080068import java.util.concurrent.ExecutionException;
Jimmy Yanda878fc2016-09-02 16:32:01 -070069import java.util.concurrent.TimeUnit;
Andrea Campanella7ebfe322019-08-29 11:46:57 -070070import java.util.stream.StreamSupport;
Jimmy Yanda878fc2016-09-02 16:32:01 -070071
72import static com.google.common.base.Preconditions.checkNotNull;
MaoLu2846b112017-05-15 17:18:55 -070073import static org.onosproject.net.optical.OpticalAnnotations.INPUT_PORT_STATUS;
74import static org.onosproject.roadm.RoadmUtil.OPS_OPT_AUTO;
75import static org.onosproject.roadm.RoadmUtil.OPS_OPT_FORCE;
76import static org.onosproject.roadm.RoadmUtil.OPS_OPT_MANUAL;
Jimmy Yanda878fc2016-09-02 16:32:01 -070077
78/**
79 * Application for monitoring and configuring ROADM devices.
80 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070081@Component(immediate = true, service = RoadmService.class)
Jimmy Yanda878fc2016-09-02 16:32:01 -070082public class RoadmManager implements RoadmService {
83
84 private static final String APP_NAME = "org.onosproject.roadm";
85 private ApplicationId appId;
86
87 private final Logger log = LoggerFactory.getLogger(getClass());
88
89 private DeviceListener deviceListener = new InternalDeviceListener();
90
Ray Milkeyd84f89b2018-08-17 14:54:17 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070092 protected RoadmStore roadmStore;
93
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070095 protected CoreService coreService;
96
Ray Milkeyd84f89b2018-08-17 14:54:17 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070098 protected DeviceService deviceService;
99
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -0700101 protected FlowRuleService flowRuleService;
102
103 @Activate
104 protected void activate() {
105 appId = coreService.registerApplication(APP_NAME);
106 deviceService.addListener(deviceListener);
107 initDevices();
108
109 log.info("Started");
110 }
111
112 @Deactivate
113 protected void deactivate() {
114 deviceService.removeListener(deviceListener);
115
116 log.info("Stopped");
117 }
118
MaoLu2846b112017-05-15 17:18:55 -0700119 @Deprecated
MaoLu937cf422017-03-03 23:31:46 -0800120 @Override
121 public void setProtectionSwitchWorkingPath(DeviceId deviceId, int index) {
122 checkNotNull(deviceId);
123 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
124 if (behaviour == null) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700125 return;
126 }
MaoLu937cf422017-03-03 23:31:46 -0800127 Map<ConnectPoint, ProtectedTransportEndpointState> map = getProtectionSwitchStates(behaviour);
128 if (map == null) {
129 log.warn("Failed to get protected transport endpoint state in device {}", deviceId);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700130 return;
131 }
MaoLu937cf422017-03-03 23:31:46 -0800132 if (map.isEmpty()) {
133 log.warn("No protected transport endpoint state found in device {}", deviceId);
134 return;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700135 }
Ray Milkey4f7e3632019-02-19 15:35:20 -0800136 behaviour.switchToManual(map.keySet().toArray(new ConnectPoint[0])[0], index);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700137 }
138
MaoLu2846b112017-05-15 17:18:55 -0700139 @Deprecated
MaoLu937cf422017-03-03 23:31:46 -0800140 @Override
141 public String getProtectionSwitchPortState(DeviceId deviceId, PortNumber portNumber) {
142 checkNotNull(deviceId);
143 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
144 if (behaviour == null) {
145 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700146 }
MaoLu937cf422017-03-03 23:31:46 -0800147 Map<ConnectPoint, ProtectedTransportEndpointState> map = getProtectionSwitchStates(behaviour);
148 if (map == null) {
149 log.warn("Failed to get protected transport endpoint state in device {}", deviceId);
150 return null;
151 }
152 for (ProtectedTransportEndpointState state : map.values()) {
153 for (TransportEndpointState element : state.pathStates()) {
154 if (element.description().output().connectPoint().port().equals(portNumber)) {
MaoLu2846b112017-05-15 17:18:55 -0700155 return element.attributes().get(INPUT_PORT_STATUS);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700156 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700157 }
158 }
MaoLudd5a00b2017-03-14 11:19:48 -0700159 // Do not need warning here for port polling.
160 log.debug("Unable to get port status, device: {}, port: {}", deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800161 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700162 }
163
164 @Override
MaoLu2846b112017-05-15 17:18:55 -0700165 public void configProtectionSwitch(DeviceId deviceId, String operation, ConnectPoint identifier, int index) {
166 checkNotNull(deviceId);
167 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
168 if (behaviour == null) {
169 return;
170 }
171 // automatic operation
172 if (OPS_OPT_AUTO.equals(operation)) {
173 behaviour.switchToAutomatic(identifier);
174 return;
175 }
176 // force or manual operation
177 if (OPS_OPT_MANUAL.equals(operation)) {
178 behaviour.switchToManual(identifier, index);
179 } else if (OPS_OPT_FORCE.equals(operation)) {
180 behaviour.switchToForce(identifier, index);
181 }
182 }
183
184 @Override
185 public Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(DeviceId deviceId) {
186 checkNotNull(deviceId);
187 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
188 if (behaviour == null) {
189 return ImmutableMap.of();
190 }
191 return getProtectionSwitchStates(behaviour);
192 }
193
194
195 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200196 public void setTargetPortPower(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700197 checkNotNull(deviceId);
198 checkNotNull(portNumber);
199 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
200 if (powerConfig != null) {
201 roadmStore.setTargetPower(deviceId, portNumber, power);
202 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
203 } else {
204 log.warn("Unable to set target port power for device {}", deviceId);
205 }
206 }
207
208 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200209 public Double getTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700210 checkNotNull(deviceId);
211 checkNotNull(portNumber);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700212 // Request target port power when it doesn't exist. Inactive updating mode.
Andrea Campanelladadf6402019-08-07 15:24:11 +0200213 Double power = roadmStore.getTargetPower(deviceId, portNumber);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700214 if (power == null) {
215 return syncTargetPortPower(deviceId, portNumber);
216 }
217 return power;
218 }
219
220 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200221 public Double syncTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700222 checkNotNull(deviceId);
223 checkNotNull(portNumber);
224 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
225 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200226 Optional<Double> pl = powerConfig.getTargetPower(portNumber, Direction.ALL);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700227 if (pl.isPresent()) {
228 roadmStore.setTargetPower(deviceId, portNumber, pl.get());
229 return pl.get();
230 } else {
231 roadmStore.removeTargetPower(deviceId, portNumber);
232 }
233 }
234 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700235 }
236
237 @Override
238 public void setAttenuation(DeviceId deviceId, PortNumber portNumber,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200239 OchSignal ochSignal, double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700240 checkNotNull(deviceId);
241 checkNotNull(portNumber);
242 checkNotNull(ochSignal);
243 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
244 if (powerConfig != null) {
245 powerConfig.setTargetPower(portNumber, ochSignal, attenuation);
246 } else {
247 log.warn("Cannot set attenuation for channel index {} on device {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200248 ochSignal.spacingMultiplier(), deviceId);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700249 }
250 }
251
252 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200253 public Double getAttenuation(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700254 checkNotNull(deviceId);
255 checkNotNull(portNumber);
256 checkNotNull(ochSignal);
257 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
258 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200259 Optional<Double> attenuation = powerConfig.getTargetPower(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700260 if (attenuation.isPresent()) {
261 return attenuation.get();
262 }
263 }
264 return null;
265 }
266
267 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200268 public Double getCurrentPortPower(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700269 checkNotNull(deviceId);
270 checkNotNull(portNumber);
271 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
272 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200273 Optional<Double> currentPower = powerConfig.currentPower(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700274 if (currentPower.isPresent()) {
275 return currentPower.get();
276 }
277 }
278 return null;
279 }
280
281 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200282 public Double getCurrentChannelPower(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700283 checkNotNull(deviceId);
284 checkNotNull(portNumber);
285 checkNotNull(ochSignal);
286 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
287 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200288 Optional<Double> currentPower = powerConfig.currentPower(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700289 if (currentPower.isPresent()) {
290 return currentPower.get();
291 }
292 }
293 return null;
294 }
295
296 @Override
297 public Set<OchSignal> queryLambdas(DeviceId deviceId, PortNumber portNumber) {
298 checkNotNull(deviceId);
299 checkNotNull(portNumber);
300 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
301 if (lambdaQuery != null) {
302 return lambdaQuery.queryLambdas(portNumber);
303 }
304 return Collections.emptySet();
305 }
306
307 @Override
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200308 public ModulationScheme getModulation(DeviceId deviceId, PortNumber portNumber) {
309 checkNotNull(deviceId);
310 checkNotNull(portNumber);
311 Device device = deviceService.getDevice(deviceId);
312 Direction component = Direction.ALL;
313 if (device.is(ModulationConfig.class)) {
314 ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
315 Optional<ModulationScheme> scheme = modulationConfig.getModulationScheme(portNumber, component);
316 if (scheme.isPresent()) {
317 return scheme.get();
318 }
319 }
320 return null;
321 }
322
323 @Override
324 public void setModulation(DeviceId deviceId, PortNumber portNumber, String modulation) {
325 checkNotNull(deviceId);
326 checkNotNull(portNumber);
327 Device device = deviceService.getDevice(deviceId);
328 Direction component = Direction.ALL;
329 if (device.is(ModulationConfig.class)) {
330 ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
331 long bitRate = 0;
332 if (modulation.equals(ModulationScheme.DP_QPSK.name())) {
333 bitRate = 100;
334 } else {
335 bitRate = 200;
336 }
337 modulationConfig.setModulationScheme(portNumber, component, bitRate);
338 }
339
340 }
341
342 @Override
Jimmy Yanda878fc2016-09-02 16:32:01 -0700343 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200344 int timeout, PortNumber inPort, PortNumber outPort, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700345 checkNotNull(deviceId);
346 checkNotNull(inPort);
347 checkNotNull(outPort);
348
MaoLu937cf422017-03-03 23:31:46 -0800349 TrafficSelector selector = DefaultTrafficSelector.builder()
350 .add(Criteria.matchInPort(inPort))
351 .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
352 .add(Criteria.matchLambda(ochSignal))
353 .build();
354 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
alessioc6f054b2019-07-22 11:05:07 +0200355 .add(Instructions.modL0Lambda(ochSignal))
MaoLu937cf422017-03-03 23:31:46 -0800356 .add(Instructions.createOutput(outPort))
357 .build();
358
359 FlowRule.Builder flowBuilder = DefaultFlowRule.builder()
360 .forDevice(deviceId)
361 .fromApp(appId)
362 .withPriority(priority)
363 .withSelector(selector)
364 .withTreatment(treatment);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700365 if (isPermanent) {
366 flowBuilder.makePermanent();
367 } else {
368 flowBuilder.makeTemporary(timeout);
369 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700370
371 FlowRule flowRule = flowBuilder.build();
372 flowRuleService.applyFlowRules(flowRule);
373
374 log.info("Created connection from input port {} to output port {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200375 inPort.toLong(), outPort.toLong());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700376
377 return flowRule.id();
378 }
379
380 @Override
381 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanella7ebfe322019-08-29 11:46:57 -0700382 int timeout, PortNumber inPort, PortNumber outPort,
383 OchSignal ochSignal, Double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700384 checkNotNull(deviceId);
385 checkNotNull(inPort);
386 checkNotNull(outPort);
MaoLu937cf422017-03-03 23:31:46 -0800387 FlowId flowId = createConnection(deviceId, priority, isPermanent, timeout, inPort, outPort, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700388 delayedSetAttenuation(deviceId, outPort, ochSignal, attenuation);
389 return flowId;
390 }
391
Jimmy Yanda878fc2016-09-02 16:32:01 -0700392 @Override
Andrea Campanella7ebfe322019-08-29 11:46:57 -0700393 public Frequency getWavelength(DeviceId deviceId, PortNumber portNumber) {
394 checkNotNull(deviceId);
395 checkNotNull(portNumber);
396 Optional<FlowEntry> optFlow = StreamSupport
397 .stream(flowRuleService.getFlowEntries(deviceId).spliterator(), false)
398 .filter(flow -> {
399 return flow.treatment().allInstructions().stream().filter(instr -> {
400 if (instr.type().equals(Instruction.Type.OUTPUT)) {
401 return ((Instructions.OutputInstruction) instr).port().equals(portNumber);
402 } else if (instr.type().equals(Instruction.Type.L0MODIFICATION)) {
403 return ((L0ModificationInstruction) instr).subtype()
404 .equals(L0ModificationInstruction.L0SubType.OCH);
405 }
406 return false;
407 }).count() == 2;
408 }).findFirst();
409 if (optFlow.isPresent()) {
410 Optional<Instruction> instruction = optFlow.get().treatment().allInstructions().stream().filter(instr -> {
411 if (instr.type().equals(Instruction.Type.L0MODIFICATION)) {
412 return ((L0ModificationInstruction) instr).subtype()
413 .equals(L0ModificationInstruction.L0SubType.OCH);
414 }
415 return false;
416 }).findAny();
417 if (instruction.isPresent()) {
418 return ((L0ModificationInstruction.ModOchSignalInstruction) instruction.get()).lambda()
419 .centralFrequency();
420 }
421 }
422 return null;
423 }
424
425 @Override
Jimmy Yanda878fc2016-09-02 16:32:01 -0700426 public void removeConnection(DeviceId deviceId, FlowId flowId) {
427 checkNotNull(deviceId);
428 checkNotNull(flowId);
429 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
430 if (entry.id().equals(flowId)) {
431 flowRuleService.removeFlowRules(entry);
432 log.info("Deleted connection {}", entry.id());
433 break;
434 }
435 }
436 }
437
438 @Override
439 public boolean hasPortTargetPower(DeviceId deviceId, PortNumber portNumber) {
440 checkNotNull(deviceId);
441 checkNotNull(portNumber);
442 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
443 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200444 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700445 return range.isPresent();
446 }
447 return false;
448 }
449
450 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200451 public boolean portTargetPowerInRange(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700452 checkNotNull(deviceId);
453 checkNotNull(portNumber);
454 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
455 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200456 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700457 return range.isPresent() && range.get().contains(power);
458 }
459 return false;
460 }
461
462 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200463 public boolean attenuationInRange(DeviceId deviceId, PortNumber outPort, double att) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700464 checkNotNull(deviceId);
465 checkNotNull(outPort);
466 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
467 if (powerConfig != null) {
468 OchSignal stubOch = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 0);
Andrea Campanelladadf6402019-08-07 15:24:11 +0200469 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(outPort, stubOch);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700470 return range.isPresent() && range.get().contains(att);
471 }
472 return false;
473 }
474
475 @Override
476 public boolean validInputPort(DeviceId deviceId, PortNumber portNumber) {
477 checkNotNull(deviceId);
478 checkNotNull(portNumber);
479 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
480 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200481 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700482 return range.isPresent();
483 }
484 return false;
485 }
486
487 @Override
488 public boolean validOutputPort(DeviceId deviceId, PortNumber portNumber) {
489 return hasPortTargetPower(deviceId, portNumber);
490 }
491
492 @Override
MaoLu937cf422017-03-03 23:31:46 -0800493 public boolean validChannel(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700494 checkNotNull(deviceId);
495 checkNotNull(portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800496 checkNotNull(ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700497 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
498 if (lambdaQuery != null) {
499 Set<OchSignal> channels = lambdaQuery.queryLambdas(portNumber);
500 return channels.contains(ochSignal);
501 }
502 return false;
503 }
504
505 @Override
506 public boolean channelAvailable(DeviceId deviceId, OchSignal ochSignal) {
507 checkNotNull(deviceId);
508 checkNotNull(ochSignal);
509 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
510 if (ChannelData.fromFlow(entry).ochSignal().equals(ochSignal)) {
511 return false;
512 }
513 }
514 return true;
515 }
516
517 @Override
MaoLu937cf422017-03-03 23:31:46 -0800518 public boolean validConnection(DeviceId deviceId, PortNumber inPort, PortNumber outPort) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700519 checkNotNull(deviceId);
520 checkNotNull(inPort);
521 checkNotNull(outPort);
522 return validInputPort(deviceId, inPort) && validOutputPort(deviceId, outPort);
523 }
524
525 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200526 public Range<Double> targetPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700527 checkNotNull(deviceId);
528 checkNotNull(portNumber);
529 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
530 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200531 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700532 if (range.isPresent()) {
533 return range.get();
534 }
535 }
536 return null;
537 }
538
539 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200540 public Range<Double> attenuationRange(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700541 checkNotNull(deviceId);
542 checkNotNull(portNumber);
543 checkNotNull(ochSignal);
544 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
545 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200546 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700547 if (range.isPresent()) {
548 return range.get();
549 }
550 }
551 return null;
552 }
553
554 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200555 public Range<Double> inputPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700556 checkNotNull(deviceId);
557 checkNotNull(portNumber);
558 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
559 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200560 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700561 if (range.isPresent()) {
562 return range.get();
563 }
564 }
565 return null;
566 }
567
MaoLu937cf422017-03-03 23:31:46 -0800568 private PowerConfig<Object> getPowerConfig(DeviceId deviceId) {
569 Device device = deviceService.getDevice(deviceId);
570 if (device != null && device.is(PowerConfig.class)) {
571 return device.as(PowerConfig.class);
572 }
MaoLudd5a00b2017-03-14 11:19:48 -0700573 // Do not need warning here for port polling.
574 log.debug("Unable to load PowerConfig for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800575 return null;
576 }
577
578 private LambdaQuery getLambdaQuery(DeviceId deviceId) {
579 Device device = deviceService.getDevice(deviceId);
580 if (device != null && device.is(LambdaQuery.class)) {
581 return device.as(LambdaQuery.class);
582 }
MaoLudd5a00b2017-03-14 11:19:48 -0700583 // Do not need warning here for port polling.
584 log.debug("Unable to load LambdaQuery for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800585 return null;
586 }
587
588 private ProtectionConfigBehaviour getProtectionConfig(DeviceId deviceId) {
589 Device device = deviceService.getDevice(deviceId);
590 if (device != null && device.is(ProtectionConfigBehaviour.class)) {
591 return device.as(ProtectionConfigBehaviour.class);
592 }
MaoLudd5a00b2017-03-14 11:19:48 -0700593 // Do not need warning here for port polling.
594 log.debug("Unable to load ProtectionConfigBehaviour for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800595 return null;
596 }
597
598 // Initialize all devices
599 private void initDevices() {
600 for (Device device : deviceService.getDevices(Device.Type.ROADM)) {
601 initDevice(device.id());
602 //FIXME
603 // As roadm application is a optional tool for now.
604 // The target power initialization will be enhanced later,
605 // hopefully using an formal optical subsystem.
606 // setAllInitialTargetPortPowers(device.id());
607 }
608 }
609
610 // Initialize RoadmStore for a device to support target power
611 private void initDevice(DeviceId deviceId) {
612 if (!roadmStore.deviceAvailable(deviceId)) {
613 roadmStore.addDevice(deviceId);
614 }
615 log.info("Initialized device {}", deviceId);
616 }
617
618 // Sets the target port powers for a port on a device
619 // Attempts to read target powers from store. If no value is found then
620 // default value is used instead.
621 private void setInitialTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
622 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
623 if (powerConfig == null) {
624 log.warn("Unable to set default initial powers for port {} on device {}", portNumber, deviceId);
625 return;
626 }
627
Andrea Campanelladadf6402019-08-07 15:24:11 +0200628 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800629 if (!range.isPresent()) {
630 log.warn("No target power range found for port {} on device {}", portNumber, deviceId);
631 return;
632 }
633
Andrea Campanelladadf6402019-08-07 15:24:11 +0200634 Double power = roadmStore.getTargetPower(deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800635 if (power == null) {
636 // Set default to middle of the range
637 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
638 roadmStore.setTargetPower(deviceId, portNumber, power);
639 }
640 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
641 }
642
643 // Sets the target port powers for each each port on a device
644 // Attempts to read target powers from store. If no value is found then
645 // default value is used instead
646 private void setAllInitialTargetPortPowers(DeviceId deviceId) {
647 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
648 if (powerConfig == null) {
649 log.warn("Unable to set default initial powers for device {}", deviceId);
650 return;
651 }
652
653 List<Port> ports = deviceService.getPorts(deviceId);
654 for (Port port : ports) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200655 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(port.number(), Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800656 if (range.isPresent()) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200657 Double power = roadmStore.getTargetPower(deviceId, port.number());
MaoLu937cf422017-03-03 23:31:46 -0800658 if (power == null) {
659 // Set default to middle of the range
660 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
661 roadmStore.setTargetPower(deviceId, port.number(), power);
662 }
663 powerConfig.setTargetPower(port.number(), Direction.ALL, power);
664 } else {
665 log.warn("No target power range found for port {} on device {}", port.number(), deviceId);
666 }
667 }
668 }
669
670 // Delay the call to setTargetPower because the flow may not be in the store yet
alessio1bf2a632019-06-04 15:47:39 +0200671 // Tested with Lumentum ROADM-20 1 seconds was not enough, increased to 5 seconds
MaoLu937cf422017-03-03 23:31:46 -0800672 private void delayedSetAttenuation(DeviceId deviceId, PortNumber outPort,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200673 OchSignal ochSignal, Double attenuation) {
MaoLu937cf422017-03-03 23:31:46 -0800674 Runnable setAtt = () -> {
675 try {
alessio1bf2a632019-06-04 15:47:39 +0200676 TimeUnit.SECONDS.sleep(5);
MaoLu937cf422017-03-03 23:31:46 -0800677 } catch (InterruptedException e) {
678 log.warn("Thread interrupted. Setting attenuation early.");
MaoLu2846b112017-05-15 17:18:55 -0700679 Thread.currentThread().interrupt();
MaoLu937cf422017-03-03 23:31:46 -0800680 }
681 setAttenuation(deviceId, outPort, ochSignal, attenuation);
682 };
683 new Thread(setAtt).start();
684 }
685
686 // get protection endpoint states
687 private Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(
688 ProtectionConfigBehaviour behaviour) {
MaoLu937cf422017-03-03 23:31:46 -0800689 Map<ConnectPoint, ProtectedTransportEndpointState> map;
690 try {
MaoLu2846b112017-05-15 17:18:55 -0700691 map = behaviour.getProtectionEndpointStates().get();
MaoLu937cf422017-03-03 23:31:46 -0800692 } catch (InterruptedException e1) {
693 log.error("Interrupted.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700694 Thread.currentThread().interrupt();
695 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800696 } catch (ExecutionException e1) {
697 log.error("Exception caught.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700698 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800699 }
700 return map;
701 }
702
Jimmy Yanda878fc2016-09-02 16:32:01 -0700703 // Listens to device events.
704 private class InternalDeviceListener implements DeviceListener {
705 @Override
706 public void event(DeviceEvent deviceEvent) {
707 Device device = deviceEvent.subject();
708
709 switch (deviceEvent.type()) {
710 case DEVICE_ADDED:
711 case DEVICE_UPDATED:
712 initDevice(device.id());
713 break;
714 case PORT_ADDED:
715 case PORT_UPDATED:
MaoLu937cf422017-03-03 23:31:46 -0800716 //FIXME
717 // As roadm application is a optional tool for now.
718 // The target power initialization will be enhanced later,
719 // hopefully using an formal optical subsystem.
720 // setInitialTargetPortPower(device.id(), deviceEvent.port().number());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700721 break;
722 default:
723 break;
724
725 }
726 }
727 }
728}