blob: 2cbc711fd493b61bf91fbaea4c0e0d5fa1613f9a [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;
alessio2f72af42019-12-13 10:29:22 +010031import org.onosproject.net.OchSignalType;
Jimmy Yanda878fc2016-09-02 16:32:01 -070032import 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 Campanella02e2eb4e2019-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 Campanella02e2eb4e2019-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 Campanella02e2eb4e2019-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;
Andrea Campanella1ac57982019-08-30 11:08:57 -0700332 if (modulation.equalsIgnoreCase(ModulationScheme.DP_QPSK.name())) {
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200333 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
alessio2f72af42019-12-13 10:29:22 +0100349 //Creation of selector.
MaoLu937cf422017-03-03 23:31:46 -0800350 TrafficSelector selector = DefaultTrafficSelector.builder()
351 .add(Criteria.matchInPort(inPort))
alessio2f72af42019-12-13 10:29:22 +0100352 .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
353 .add(Criteria.matchLambda(ochSignal))
MaoLu937cf422017-03-03 23:31:46 -0800354 .build();
alessio2f72af42019-12-13 10:29:22 +0100355
356 //Creation of treatment
MaoLu937cf422017-03-03 23:31:46 -0800357 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
alessioc6f054b2019-07-22 11:05:07 +0200358 .add(Instructions.modL0Lambda(ochSignal))
MaoLu937cf422017-03-03 23:31:46 -0800359 .add(Instructions.createOutput(outPort))
360 .build();
361
362 FlowRule.Builder flowBuilder = DefaultFlowRule.builder()
363 .forDevice(deviceId)
364 .fromApp(appId)
365 .withPriority(priority)
366 .withSelector(selector)
367 .withTreatment(treatment);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700368 if (isPermanent) {
369 flowBuilder.makePermanent();
370 } else {
371 flowBuilder.makeTemporary(timeout);
372 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700373
374 FlowRule flowRule = flowBuilder.build();
375 flowRuleService.applyFlowRules(flowRule);
376
377 log.info("Created connection from input port {} to output port {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200378 inPort.toLong(), outPort.toLong());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700379
380 return flowRule.id();
381 }
382
383 @Override
384 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -0700385 int timeout, PortNumber inPort, PortNumber outPort,
386 OchSignal ochSignal, Double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700387 checkNotNull(deviceId);
388 checkNotNull(inPort);
389 checkNotNull(outPort);
MaoLu937cf422017-03-03 23:31:46 -0800390 FlowId flowId = createConnection(deviceId, priority, isPermanent, timeout, inPort, outPort, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700391 delayedSetAttenuation(deviceId, outPort, ochSignal, attenuation);
392 return flowId;
393 }
394
Jimmy Yanda878fc2016-09-02 16:32:01 -0700395 @Override
Andrea Campanella02e2eb4e2019-08-29 11:46:57 -0700396 public Frequency getWavelength(DeviceId deviceId, PortNumber portNumber) {
397 checkNotNull(deviceId);
398 checkNotNull(portNumber);
399 Optional<FlowEntry> optFlow = StreamSupport
400 .stream(flowRuleService.getFlowEntries(deviceId).spliterator(), false)
401 .filter(flow -> {
402 return flow.treatment().allInstructions().stream().filter(instr -> {
403 if (instr.type().equals(Instruction.Type.OUTPUT)) {
404 return ((Instructions.OutputInstruction) instr).port().equals(portNumber);
405 } else if (instr.type().equals(Instruction.Type.L0MODIFICATION)) {
406 return ((L0ModificationInstruction) instr).subtype()
407 .equals(L0ModificationInstruction.L0SubType.OCH);
408 }
409 return false;
410 }).count() == 2;
411 }).findFirst();
412 if (optFlow.isPresent()) {
413 Optional<Instruction> instruction = optFlow.get().treatment().allInstructions().stream().filter(instr -> {
414 if (instr.type().equals(Instruction.Type.L0MODIFICATION)) {
415 return ((L0ModificationInstruction) instr).subtype()
416 .equals(L0ModificationInstruction.L0SubType.OCH);
417 }
418 return false;
419 }).findAny();
420 if (instruction.isPresent()) {
421 return ((L0ModificationInstruction.ModOchSignalInstruction) instruction.get()).lambda()
422 .centralFrequency();
423 }
424 }
425 return null;
426 }
427
428 @Override
Jimmy Yanda878fc2016-09-02 16:32:01 -0700429 public void removeConnection(DeviceId deviceId, FlowId flowId) {
430 checkNotNull(deviceId);
431 checkNotNull(flowId);
432 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
433 if (entry.id().equals(flowId)) {
434 flowRuleService.removeFlowRules(entry);
435 log.info("Deleted connection {}", entry.id());
436 break;
437 }
438 }
439 }
440
441 @Override
442 public boolean hasPortTargetPower(DeviceId deviceId, PortNumber portNumber) {
443 checkNotNull(deviceId);
444 checkNotNull(portNumber);
445 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
446 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200447 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700448 return range.isPresent();
449 }
450 return false;
451 }
452
453 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200454 public boolean portTargetPowerInRange(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700455 checkNotNull(deviceId);
456 checkNotNull(portNumber);
457 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
458 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200459 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700460 return range.isPresent() && range.get().contains(power);
461 }
462 return false;
463 }
464
465 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200466 public boolean attenuationInRange(DeviceId deviceId, PortNumber outPort, double att) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700467 checkNotNull(deviceId);
468 checkNotNull(outPort);
469 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
470 if (powerConfig != null) {
471 OchSignal stubOch = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 0);
Andrea Campanelladadf6402019-08-07 15:24:11 +0200472 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(outPort, stubOch);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700473 return range.isPresent() && range.get().contains(att);
474 }
475 return false;
476 }
477
478 @Override
479 public boolean validInputPort(DeviceId deviceId, PortNumber portNumber) {
480 checkNotNull(deviceId);
481 checkNotNull(portNumber);
482 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
483 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200484 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700485 return range.isPresent();
486 }
487 return false;
488 }
489
490 @Override
491 public boolean validOutputPort(DeviceId deviceId, PortNumber portNumber) {
492 return hasPortTargetPower(deviceId, portNumber);
493 }
494
495 @Override
MaoLu937cf422017-03-03 23:31:46 -0800496 public boolean validChannel(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700497 checkNotNull(deviceId);
498 checkNotNull(portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800499 checkNotNull(ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700500 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
501 if (lambdaQuery != null) {
502 Set<OchSignal> channels = lambdaQuery.queryLambdas(portNumber);
503 return channels.contains(ochSignal);
504 }
505 return false;
506 }
507
508 @Override
509 public boolean channelAvailable(DeviceId deviceId, OchSignal ochSignal) {
510 checkNotNull(deviceId);
511 checkNotNull(ochSignal);
512 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
513 if (ChannelData.fromFlow(entry).ochSignal().equals(ochSignal)) {
514 return false;
515 }
516 }
517 return true;
518 }
519
520 @Override
MaoLu937cf422017-03-03 23:31:46 -0800521 public boolean validConnection(DeviceId deviceId, PortNumber inPort, PortNumber outPort) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700522 checkNotNull(deviceId);
523 checkNotNull(inPort);
524 checkNotNull(outPort);
525 return validInputPort(deviceId, inPort) && validOutputPort(deviceId, outPort);
526 }
527
528 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200529 public Range<Double> targetPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700530 checkNotNull(deviceId);
531 checkNotNull(portNumber);
532 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
533 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200534 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700535 if (range.isPresent()) {
536 return range.get();
537 }
538 }
539 return null;
540 }
541
542 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200543 public Range<Double> attenuationRange(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700544 checkNotNull(deviceId);
545 checkNotNull(portNumber);
546 checkNotNull(ochSignal);
547 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
548 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200549 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700550 if (range.isPresent()) {
551 return range.get();
552 }
553 }
554 return null;
555 }
556
557 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200558 public Range<Double> inputPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700559 checkNotNull(deviceId);
560 checkNotNull(portNumber);
561 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
562 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200563 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700564 if (range.isPresent()) {
565 return range.get();
566 }
567 }
568 return null;
569 }
570
MaoLu937cf422017-03-03 23:31:46 -0800571 private PowerConfig<Object> getPowerConfig(DeviceId deviceId) {
572 Device device = deviceService.getDevice(deviceId);
573 if (device != null && device.is(PowerConfig.class)) {
574 return device.as(PowerConfig.class);
575 }
MaoLudd5a00b2017-03-14 11:19:48 -0700576 // Do not need warning here for port polling.
577 log.debug("Unable to load PowerConfig for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800578 return null;
579 }
580
581 private LambdaQuery getLambdaQuery(DeviceId deviceId) {
582 Device device = deviceService.getDevice(deviceId);
583 if (device != null && device.is(LambdaQuery.class)) {
584 return device.as(LambdaQuery.class);
585 }
MaoLudd5a00b2017-03-14 11:19:48 -0700586 // Do not need warning here for port polling.
587 log.debug("Unable to load LambdaQuery for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800588 return null;
589 }
590
591 private ProtectionConfigBehaviour getProtectionConfig(DeviceId deviceId) {
592 Device device = deviceService.getDevice(deviceId);
593 if (device != null && device.is(ProtectionConfigBehaviour.class)) {
594 return device.as(ProtectionConfigBehaviour.class);
595 }
MaoLudd5a00b2017-03-14 11:19:48 -0700596 // Do not need warning here for port polling.
597 log.debug("Unable to load ProtectionConfigBehaviour for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800598 return null;
599 }
600
601 // Initialize all devices
602 private void initDevices() {
603 for (Device device : deviceService.getDevices(Device.Type.ROADM)) {
604 initDevice(device.id());
605 //FIXME
606 // As roadm application is a optional tool for now.
607 // The target power initialization will be enhanced later,
608 // hopefully using an formal optical subsystem.
609 // setAllInitialTargetPortPowers(device.id());
610 }
611 }
612
613 // Initialize RoadmStore for a device to support target power
614 private void initDevice(DeviceId deviceId) {
615 if (!roadmStore.deviceAvailable(deviceId)) {
616 roadmStore.addDevice(deviceId);
617 }
618 log.info("Initialized device {}", deviceId);
619 }
620
621 // Sets the target port powers for a port on a device
622 // Attempts to read target powers from store. If no value is found then
623 // default value is used instead.
624 private void setInitialTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
625 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
626 if (powerConfig == null) {
627 log.warn("Unable to set default initial powers for port {} on device {}", portNumber, deviceId);
628 return;
629 }
630
Andrea Campanelladadf6402019-08-07 15:24:11 +0200631 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800632 if (!range.isPresent()) {
633 log.warn("No target power range found for port {} on device {}", portNumber, deviceId);
634 return;
635 }
636
Andrea Campanelladadf6402019-08-07 15:24:11 +0200637 Double power = roadmStore.getTargetPower(deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800638 if (power == null) {
639 // Set default to middle of the range
640 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
641 roadmStore.setTargetPower(deviceId, portNumber, power);
642 }
643 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
644 }
645
646 // Sets the target port powers for each each port on a device
647 // Attempts to read target powers from store. If no value is found then
648 // default value is used instead
649 private void setAllInitialTargetPortPowers(DeviceId deviceId) {
650 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
651 if (powerConfig == null) {
652 log.warn("Unable to set default initial powers for device {}", deviceId);
653 return;
654 }
655
656 List<Port> ports = deviceService.getPorts(deviceId);
657 for (Port port : ports) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200658 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(port.number(), Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800659 if (range.isPresent()) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200660 Double power = roadmStore.getTargetPower(deviceId, port.number());
MaoLu937cf422017-03-03 23:31:46 -0800661 if (power == null) {
662 // Set default to middle of the range
663 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
664 roadmStore.setTargetPower(deviceId, port.number(), power);
665 }
666 powerConfig.setTargetPower(port.number(), Direction.ALL, power);
667 } else {
668 log.warn("No target power range found for port {} on device {}", port.number(), deviceId);
669 }
670 }
671 }
672
673 // Delay the call to setTargetPower because the flow may not be in the store yet
alessio1bf2a632019-06-04 15:47:39 +0200674 // Tested with Lumentum ROADM-20 1 seconds was not enough, increased to 5 seconds
MaoLu937cf422017-03-03 23:31:46 -0800675 private void delayedSetAttenuation(DeviceId deviceId, PortNumber outPort,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200676 OchSignal ochSignal, Double attenuation) {
MaoLu937cf422017-03-03 23:31:46 -0800677 Runnable setAtt = () -> {
678 try {
alessio1bf2a632019-06-04 15:47:39 +0200679 TimeUnit.SECONDS.sleep(5);
MaoLu937cf422017-03-03 23:31:46 -0800680 } catch (InterruptedException e) {
681 log.warn("Thread interrupted. Setting attenuation early.");
MaoLu2846b112017-05-15 17:18:55 -0700682 Thread.currentThread().interrupt();
MaoLu937cf422017-03-03 23:31:46 -0800683 }
684 setAttenuation(deviceId, outPort, ochSignal, attenuation);
685 };
686 new Thread(setAtt).start();
687 }
688
689 // get protection endpoint states
690 private Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(
691 ProtectionConfigBehaviour behaviour) {
MaoLu937cf422017-03-03 23:31:46 -0800692 Map<ConnectPoint, ProtectedTransportEndpointState> map;
693 try {
MaoLu2846b112017-05-15 17:18:55 -0700694 map = behaviour.getProtectionEndpointStates().get();
MaoLu937cf422017-03-03 23:31:46 -0800695 } catch (InterruptedException e1) {
696 log.error("Interrupted.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700697 Thread.currentThread().interrupt();
698 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800699 } catch (ExecutionException e1) {
700 log.error("Exception caught.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700701 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800702 }
703 return map;
704 }
705
Jimmy Yanda878fc2016-09-02 16:32:01 -0700706 // Listens to device events.
707 private class InternalDeviceListener implements DeviceListener {
708 @Override
709 public void event(DeviceEvent deviceEvent) {
710 Device device = deviceEvent.subject();
711
712 switch (deviceEvent.type()) {
713 case DEVICE_ADDED:
714 case DEVICE_UPDATED:
715 initDevice(device.id());
716 break;
717 case PORT_ADDED:
718 case PORT_UPDATED:
MaoLu937cf422017-03-03 23:31:46 -0800719 //FIXME
720 // As roadm application is a optional tool for now.
721 // The target power initialization will be enhanced later,
722 // hopefully using an formal optical subsystem.
723 // setInitialTargetPortPower(device.id(), deviceEvent.port().number());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700724 break;
725 default:
726 break;
727
728 }
729 }
730 }
731}