blob: 191f608ece99dd9b0cb06d2d21f9ef99cc1a6ecb [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;
Jimmy Yanda878fc2016-09-02 16:32:01 -070020import org.onosproject.core.ApplicationId;
21import org.onosproject.core.CoreService;
22import org.onosproject.net.ChannelSpacing;
MaoLu937cf422017-03-03 23:31:46 -080023import org.onosproject.net.ConnectPoint;
Jimmy Yanda878fc2016-09-02 16:32:01 -070024import org.onosproject.net.Device;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.Direction;
Andrea Campanellabdeeda12019-08-02 16:12:05 +020027import org.onosproject.net.ModulationScheme;
Jimmy Yanda878fc2016-09-02 16:32:01 -070028import org.onosproject.net.OchSignal;
29import org.onosproject.net.OchSignalType;
30import 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;
51import org.onosproject.net.flow.instructions.Instructions;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052import org.osgi.service.component.annotations.Activate;
53import org.osgi.service.component.annotations.Component;
54import org.osgi.service.component.annotations.Deactivate;
55import org.osgi.service.component.annotations.Reference;
56import org.osgi.service.component.annotations.ReferenceCardinality;
Jimmy Yanda878fc2016-09-02 16:32:01 -070057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
60import java.util.Collections;
61import java.util.List;
MaoLu937cf422017-03-03 23:31:46 -080062import java.util.Map;
Jimmy Yanda878fc2016-09-02 16:32:01 -070063import java.util.Optional;
64import java.util.Set;
MaoLu937cf422017-03-03 23:31:46 -080065import java.util.concurrent.ExecutionException;
Jimmy Yanda878fc2016-09-02 16:32:01 -070066import java.util.concurrent.TimeUnit;
67
68import static com.google.common.base.Preconditions.checkNotNull;
MaoLu2846b112017-05-15 17:18:55 -070069import static org.onosproject.net.optical.OpticalAnnotations.INPUT_PORT_STATUS;
70import static org.onosproject.roadm.RoadmUtil.OPS_OPT_AUTO;
71import static org.onosproject.roadm.RoadmUtil.OPS_OPT_FORCE;
72import static org.onosproject.roadm.RoadmUtil.OPS_OPT_MANUAL;
Jimmy Yanda878fc2016-09-02 16:32:01 -070073
74/**
75 * Application for monitoring and configuring ROADM devices.
76 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077@Component(immediate = true, service = RoadmService.class)
Jimmy Yanda878fc2016-09-02 16:32:01 -070078public class RoadmManager implements RoadmService {
79
80 private static final String APP_NAME = "org.onosproject.roadm";
81 private ApplicationId appId;
82
83 private final Logger log = LoggerFactory.getLogger(getClass());
84
85 private DeviceListener deviceListener = new InternalDeviceListener();
86
Ray Milkeyd84f89b2018-08-17 14:54:17 -070087 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070088 protected RoadmStore roadmStore;
89
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070091 protected CoreService coreService;
92
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070094 protected DeviceService deviceService;
95
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jimmy Yanda878fc2016-09-02 16:32:01 -070097 protected FlowRuleService flowRuleService;
98
99 @Activate
100 protected void activate() {
101 appId = coreService.registerApplication(APP_NAME);
102 deviceService.addListener(deviceListener);
103 initDevices();
104
105 log.info("Started");
106 }
107
108 @Deactivate
109 protected void deactivate() {
110 deviceService.removeListener(deviceListener);
111
112 log.info("Stopped");
113 }
114
MaoLu2846b112017-05-15 17:18:55 -0700115 @Deprecated
MaoLu937cf422017-03-03 23:31:46 -0800116 @Override
117 public void setProtectionSwitchWorkingPath(DeviceId deviceId, int index) {
118 checkNotNull(deviceId);
119 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
120 if (behaviour == null) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700121 return;
122 }
MaoLu937cf422017-03-03 23:31:46 -0800123 Map<ConnectPoint, ProtectedTransportEndpointState> map = getProtectionSwitchStates(behaviour);
124 if (map == null) {
125 log.warn("Failed to get protected transport endpoint state in device {}", deviceId);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700126 return;
127 }
MaoLu937cf422017-03-03 23:31:46 -0800128 if (map.isEmpty()) {
129 log.warn("No protected transport endpoint state found in device {}", deviceId);
130 return;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700131 }
Ray Milkey4f7e3632019-02-19 15:35:20 -0800132 behaviour.switchToManual(map.keySet().toArray(new ConnectPoint[0])[0], index);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700133 }
134
MaoLu2846b112017-05-15 17:18:55 -0700135 @Deprecated
MaoLu937cf422017-03-03 23:31:46 -0800136 @Override
137 public String getProtectionSwitchPortState(DeviceId deviceId, PortNumber portNumber) {
138 checkNotNull(deviceId);
139 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
140 if (behaviour == null) {
141 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700142 }
MaoLu937cf422017-03-03 23:31:46 -0800143 Map<ConnectPoint, ProtectedTransportEndpointState> map = getProtectionSwitchStates(behaviour);
144 if (map == null) {
145 log.warn("Failed to get protected transport endpoint state in device {}", deviceId);
146 return null;
147 }
148 for (ProtectedTransportEndpointState state : map.values()) {
149 for (TransportEndpointState element : state.pathStates()) {
150 if (element.description().output().connectPoint().port().equals(portNumber)) {
MaoLu2846b112017-05-15 17:18:55 -0700151 return element.attributes().get(INPUT_PORT_STATUS);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700152 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700153 }
154 }
MaoLudd5a00b2017-03-14 11:19:48 -0700155 // Do not need warning here for port polling.
156 log.debug("Unable to get port status, device: {}, port: {}", deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800157 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700158 }
159
160 @Override
MaoLu2846b112017-05-15 17:18:55 -0700161 public void configProtectionSwitch(DeviceId deviceId, String operation, ConnectPoint identifier, int index) {
162 checkNotNull(deviceId);
163 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
164 if (behaviour == null) {
165 return;
166 }
167 // automatic operation
168 if (OPS_OPT_AUTO.equals(operation)) {
169 behaviour.switchToAutomatic(identifier);
170 return;
171 }
172 // force or manual operation
173 if (OPS_OPT_MANUAL.equals(operation)) {
174 behaviour.switchToManual(identifier, index);
175 } else if (OPS_OPT_FORCE.equals(operation)) {
176 behaviour.switchToForce(identifier, index);
177 }
178 }
179
180 @Override
181 public Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(DeviceId deviceId) {
182 checkNotNull(deviceId);
183 ProtectionConfigBehaviour behaviour = getProtectionConfig(deviceId);
184 if (behaviour == null) {
185 return ImmutableMap.of();
186 }
187 return getProtectionSwitchStates(behaviour);
188 }
189
190
191 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200192 public void setTargetPortPower(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700193 checkNotNull(deviceId);
194 checkNotNull(portNumber);
195 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
196 if (powerConfig != null) {
197 roadmStore.setTargetPower(deviceId, portNumber, power);
198 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
199 } else {
200 log.warn("Unable to set target port power for device {}", deviceId);
201 }
202 }
203
204 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200205 public Double getTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700206 checkNotNull(deviceId);
207 checkNotNull(portNumber);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700208 // Request target port power when it doesn't exist. Inactive updating mode.
Andrea Campanelladadf6402019-08-07 15:24:11 +0200209 Double power = roadmStore.getTargetPower(deviceId, portNumber);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700210 if (power == null) {
211 return syncTargetPortPower(deviceId, portNumber);
212 }
213 return power;
214 }
215
216 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200217 public Double syncTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700218 checkNotNull(deviceId);
219 checkNotNull(portNumber);
220 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
221 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200222 Optional<Double> pl = powerConfig.getTargetPower(portNumber, Direction.ALL);
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700223 if (pl.isPresent()) {
224 roadmStore.setTargetPower(deviceId, portNumber, pl.get());
225 return pl.get();
226 } else {
227 roadmStore.removeTargetPower(deviceId, portNumber);
228 }
229 }
230 return null;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700231 }
232
233 @Override
234 public void setAttenuation(DeviceId deviceId, PortNumber portNumber,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200235 OchSignal ochSignal, double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700236 checkNotNull(deviceId);
237 checkNotNull(portNumber);
238 checkNotNull(ochSignal);
239 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
240 if (powerConfig != null) {
241 powerConfig.setTargetPower(portNumber, ochSignal, attenuation);
242 } else {
243 log.warn("Cannot set attenuation for channel index {} on device {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200244 ochSignal.spacingMultiplier(), deviceId);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700245 }
246 }
247
248 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200249 public Double getAttenuation(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700250 checkNotNull(deviceId);
251 checkNotNull(portNumber);
252 checkNotNull(ochSignal);
253 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
254 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200255 Optional<Double> attenuation = powerConfig.getTargetPower(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700256 if (attenuation.isPresent()) {
257 return attenuation.get();
258 }
259 }
260 return null;
261 }
262
263 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200264 public Double getCurrentPortPower(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700265 checkNotNull(deviceId);
266 checkNotNull(portNumber);
267 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
268 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200269 Optional<Double> currentPower = powerConfig.currentPower(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700270 if (currentPower.isPresent()) {
271 return currentPower.get();
272 }
273 }
274 return null;
275 }
276
277 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200278 public Double getCurrentChannelPower(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700279 checkNotNull(deviceId);
280 checkNotNull(portNumber);
281 checkNotNull(ochSignal);
282 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
283 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200284 Optional<Double> currentPower = powerConfig.currentPower(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700285 if (currentPower.isPresent()) {
286 return currentPower.get();
287 }
288 }
289 return null;
290 }
291
292 @Override
293 public Set<OchSignal> queryLambdas(DeviceId deviceId, PortNumber portNumber) {
294 checkNotNull(deviceId);
295 checkNotNull(portNumber);
296 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
297 if (lambdaQuery != null) {
298 return lambdaQuery.queryLambdas(portNumber);
299 }
300 return Collections.emptySet();
301 }
302
303 @Override
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200304 public ModulationScheme getModulation(DeviceId deviceId, PortNumber portNumber) {
305 checkNotNull(deviceId);
306 checkNotNull(portNumber);
307 Device device = deviceService.getDevice(deviceId);
308 Direction component = Direction.ALL;
309 if (device.is(ModulationConfig.class)) {
310 ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
311 Optional<ModulationScheme> scheme = modulationConfig.getModulationScheme(portNumber, component);
312 if (scheme.isPresent()) {
313 return scheme.get();
314 }
315 }
316 return null;
317 }
318
319 @Override
320 public void setModulation(DeviceId deviceId, PortNumber portNumber, String modulation) {
321 checkNotNull(deviceId);
322 checkNotNull(portNumber);
323 Device device = deviceService.getDevice(deviceId);
324 Direction component = Direction.ALL;
325 if (device.is(ModulationConfig.class)) {
326 ModulationConfig<Object> modulationConfig = device.as(ModulationConfig.class);
327 long bitRate = 0;
328 if (modulation.equals(ModulationScheme.DP_QPSK.name())) {
329 bitRate = 100;
330 } else {
331 bitRate = 200;
332 }
333 modulationConfig.setModulationScheme(portNumber, component, bitRate);
334 }
335
336 }
337
338 @Override
Jimmy Yanda878fc2016-09-02 16:32:01 -0700339 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200340 int timeout, PortNumber inPort, PortNumber outPort, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700341 checkNotNull(deviceId);
342 checkNotNull(inPort);
343 checkNotNull(outPort);
344
MaoLu937cf422017-03-03 23:31:46 -0800345 TrafficSelector selector = DefaultTrafficSelector.builder()
346 .add(Criteria.matchInPort(inPort))
347 .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID))
348 .add(Criteria.matchLambda(ochSignal))
349 .build();
350 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
alessioc6f054b2019-07-22 11:05:07 +0200351 .add(Instructions.modL0Lambda(ochSignal))
MaoLu937cf422017-03-03 23:31:46 -0800352 .add(Instructions.createOutput(outPort))
353 .build();
354
355 FlowRule.Builder flowBuilder = DefaultFlowRule.builder()
356 .forDevice(deviceId)
357 .fromApp(appId)
358 .withPriority(priority)
359 .withSelector(selector)
360 .withTreatment(treatment);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700361 if (isPermanent) {
362 flowBuilder.makePermanent();
363 } else {
364 flowBuilder.makeTemporary(timeout);
365 }
Jimmy Yanda878fc2016-09-02 16:32:01 -0700366
367 FlowRule flowRule = flowBuilder.build();
368 flowRuleService.applyFlowRules(flowRule);
369
370 log.info("Created connection from input port {} to output port {}",
Andrea Campanellabdeeda12019-08-02 16:12:05 +0200371 inPort.toLong(), outPort.toLong());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700372
373 return flowRule.id();
374 }
375
376 @Override
377 public FlowId createConnection(DeviceId deviceId, int priority, boolean isPermanent,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200378 int timeout, PortNumber inPort, PortNumber outPort,
379 OchSignal ochSignal, Double attenuation) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700380 checkNotNull(deviceId);
381 checkNotNull(inPort);
382 checkNotNull(outPort);
MaoLu937cf422017-03-03 23:31:46 -0800383 FlowId flowId = createConnection(deviceId, priority, isPermanent, timeout, inPort, outPort, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700384 delayedSetAttenuation(deviceId, outPort, ochSignal, attenuation);
385 return flowId;
386 }
387
Jimmy Yanda878fc2016-09-02 16:32:01 -0700388 @Override
389 public void removeConnection(DeviceId deviceId, FlowId flowId) {
390 checkNotNull(deviceId);
391 checkNotNull(flowId);
392 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
393 if (entry.id().equals(flowId)) {
394 flowRuleService.removeFlowRules(entry);
395 log.info("Deleted connection {}", entry.id());
396 break;
397 }
398 }
399 }
400
401 @Override
402 public boolean hasPortTargetPower(DeviceId deviceId, PortNumber portNumber) {
403 checkNotNull(deviceId);
404 checkNotNull(portNumber);
405 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
406 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200407 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700408 return range.isPresent();
409 }
410 return false;
411 }
412
413 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200414 public boolean portTargetPowerInRange(DeviceId deviceId, PortNumber portNumber, double power) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700415 checkNotNull(deviceId);
416 checkNotNull(portNumber);
417 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
418 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200419 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700420 return range.isPresent() && range.get().contains(power);
421 }
422 return false;
423 }
424
425 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200426 public boolean attenuationInRange(DeviceId deviceId, PortNumber outPort, double att) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700427 checkNotNull(deviceId);
428 checkNotNull(outPort);
429 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
430 if (powerConfig != null) {
431 OchSignal stubOch = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 0);
Andrea Campanelladadf6402019-08-07 15:24:11 +0200432 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(outPort, stubOch);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700433 return range.isPresent() && range.get().contains(att);
434 }
435 return false;
436 }
437
438 @Override
439 public boolean validInputPort(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.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700445 return range.isPresent();
446 }
447 return false;
448 }
449
450 @Override
451 public boolean validOutputPort(DeviceId deviceId, PortNumber portNumber) {
452 return hasPortTargetPower(deviceId, portNumber);
453 }
454
455 @Override
MaoLu937cf422017-03-03 23:31:46 -0800456 public boolean validChannel(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700457 checkNotNull(deviceId);
458 checkNotNull(portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800459 checkNotNull(ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700460 LambdaQuery lambdaQuery = getLambdaQuery(deviceId);
461 if (lambdaQuery != null) {
462 Set<OchSignal> channels = lambdaQuery.queryLambdas(portNumber);
463 return channels.contains(ochSignal);
464 }
465 return false;
466 }
467
468 @Override
469 public boolean channelAvailable(DeviceId deviceId, OchSignal ochSignal) {
470 checkNotNull(deviceId);
471 checkNotNull(ochSignal);
472 for (FlowEntry entry : flowRuleService.getFlowEntries(deviceId)) {
473 if (ChannelData.fromFlow(entry).ochSignal().equals(ochSignal)) {
474 return false;
475 }
476 }
477 return true;
478 }
479
480 @Override
MaoLu937cf422017-03-03 23:31:46 -0800481 public boolean validConnection(DeviceId deviceId, PortNumber inPort, PortNumber outPort) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700482 checkNotNull(deviceId);
483 checkNotNull(inPort);
484 checkNotNull(outPort);
485 return validInputPort(deviceId, inPort) && validOutputPort(deviceId, outPort);
486 }
487
488 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200489 public Range<Double> targetPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700490 checkNotNull(deviceId);
491 checkNotNull(portNumber);
492 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
493 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200494 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700495 if (range.isPresent()) {
496 return range.get();
497 }
498 }
499 return null;
500 }
501
502 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200503 public Range<Double> attenuationRange(DeviceId deviceId, PortNumber portNumber, OchSignal ochSignal) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700504 checkNotNull(deviceId);
505 checkNotNull(portNumber);
506 checkNotNull(ochSignal);
507 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
508 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200509 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, ochSignal);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700510 if (range.isPresent()) {
511 return range.get();
512 }
513 }
514 return null;
515 }
516
517 @Override
Andrea Campanelladadf6402019-08-07 15:24:11 +0200518 public Range<Double> inputPortPowerRange(DeviceId deviceId, PortNumber portNumber) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700519 checkNotNull(deviceId);
520 checkNotNull(portNumber);
521 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
522 if (powerConfig != null) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200523 Optional<Range<Double>> range = powerConfig.getInputPowerRange(portNumber, Direction.ALL);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700524 if (range.isPresent()) {
525 return range.get();
526 }
527 }
528 return null;
529 }
530
MaoLu937cf422017-03-03 23:31:46 -0800531 private PowerConfig<Object> getPowerConfig(DeviceId deviceId) {
532 Device device = deviceService.getDevice(deviceId);
533 if (device != null && device.is(PowerConfig.class)) {
534 return device.as(PowerConfig.class);
535 }
MaoLudd5a00b2017-03-14 11:19:48 -0700536 // Do not need warning here for port polling.
537 log.debug("Unable to load PowerConfig for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800538 return null;
539 }
540
541 private LambdaQuery getLambdaQuery(DeviceId deviceId) {
542 Device device = deviceService.getDevice(deviceId);
543 if (device != null && device.is(LambdaQuery.class)) {
544 return device.as(LambdaQuery.class);
545 }
MaoLudd5a00b2017-03-14 11:19:48 -0700546 // Do not need warning here for port polling.
547 log.debug("Unable to load LambdaQuery for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800548 return null;
549 }
550
551 private ProtectionConfigBehaviour getProtectionConfig(DeviceId deviceId) {
552 Device device = deviceService.getDevice(deviceId);
553 if (device != null && device.is(ProtectionConfigBehaviour.class)) {
554 return device.as(ProtectionConfigBehaviour.class);
555 }
MaoLudd5a00b2017-03-14 11:19:48 -0700556 // Do not need warning here for port polling.
557 log.debug("Unable to load ProtectionConfigBehaviour for {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800558 return null;
559 }
560
561 // Initialize all devices
562 private void initDevices() {
563 for (Device device : deviceService.getDevices(Device.Type.ROADM)) {
564 initDevice(device.id());
565 //FIXME
566 // As roadm application is a optional tool for now.
567 // The target power initialization will be enhanced later,
568 // hopefully using an formal optical subsystem.
569 // setAllInitialTargetPortPowers(device.id());
570 }
571 }
572
573 // Initialize RoadmStore for a device to support target power
574 private void initDevice(DeviceId deviceId) {
575 if (!roadmStore.deviceAvailable(deviceId)) {
576 roadmStore.addDevice(deviceId);
577 }
578 log.info("Initialized device {}", deviceId);
579 }
580
581 // Sets the target port powers for a port on a device
582 // Attempts to read target powers from store. If no value is found then
583 // default value is used instead.
584 private void setInitialTargetPortPower(DeviceId deviceId, PortNumber portNumber) {
585 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
586 if (powerConfig == null) {
587 log.warn("Unable to set default initial powers for port {} on device {}", portNumber, deviceId);
588 return;
589 }
590
Andrea Campanelladadf6402019-08-07 15:24:11 +0200591 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(portNumber, Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800592 if (!range.isPresent()) {
593 log.warn("No target power range found for port {} on device {}", portNumber, deviceId);
594 return;
595 }
596
Andrea Campanelladadf6402019-08-07 15:24:11 +0200597 Double power = roadmStore.getTargetPower(deviceId, portNumber);
MaoLu937cf422017-03-03 23:31:46 -0800598 if (power == null) {
599 // Set default to middle of the range
600 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
601 roadmStore.setTargetPower(deviceId, portNumber, power);
602 }
603 powerConfig.setTargetPower(portNumber, Direction.ALL, power);
604 }
605
606 // Sets the target port powers for each each port on a device
607 // Attempts to read target powers from store. If no value is found then
608 // default value is used instead
609 private void setAllInitialTargetPortPowers(DeviceId deviceId) {
610 PowerConfig<Object> powerConfig = getPowerConfig(deviceId);
611 if (powerConfig == null) {
612 log.warn("Unable to set default initial powers for device {}", deviceId);
613 return;
614 }
615
616 List<Port> ports = deviceService.getPorts(deviceId);
617 for (Port port : ports) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200618 Optional<Range<Double>> range = powerConfig.getTargetPowerRange(port.number(), Direction.ALL);
MaoLu937cf422017-03-03 23:31:46 -0800619 if (range.isPresent()) {
Andrea Campanelladadf6402019-08-07 15:24:11 +0200620 Double power = roadmStore.getTargetPower(deviceId, port.number());
MaoLu937cf422017-03-03 23:31:46 -0800621 if (power == null) {
622 // Set default to middle of the range
623 power = (range.get().lowerEndpoint() + range.get().upperEndpoint()) / 2;
624 roadmStore.setTargetPower(deviceId, port.number(), power);
625 }
626 powerConfig.setTargetPower(port.number(), Direction.ALL, power);
627 } else {
628 log.warn("No target power range found for port {} on device {}", port.number(), deviceId);
629 }
630 }
631 }
632
633 // Delay the call to setTargetPower because the flow may not be in the store yet
alessio1bf2a632019-06-04 15:47:39 +0200634 // Tested with Lumentum ROADM-20 1 seconds was not enough, increased to 5 seconds
MaoLu937cf422017-03-03 23:31:46 -0800635 private void delayedSetAttenuation(DeviceId deviceId, PortNumber outPort,
Andrea Campanelladadf6402019-08-07 15:24:11 +0200636 OchSignal ochSignal, Double attenuation) {
MaoLu937cf422017-03-03 23:31:46 -0800637 Runnable setAtt = () -> {
638 try {
alessio1bf2a632019-06-04 15:47:39 +0200639 TimeUnit.SECONDS.sleep(5);
MaoLu937cf422017-03-03 23:31:46 -0800640 } catch (InterruptedException e) {
641 log.warn("Thread interrupted. Setting attenuation early.");
MaoLu2846b112017-05-15 17:18:55 -0700642 Thread.currentThread().interrupt();
MaoLu937cf422017-03-03 23:31:46 -0800643 }
644 setAttenuation(deviceId, outPort, ochSignal, attenuation);
645 };
646 new Thread(setAtt).start();
647 }
648
649 // get protection endpoint states
650 private Map<ConnectPoint, ProtectedTransportEndpointState> getProtectionSwitchStates(
651 ProtectionConfigBehaviour behaviour) {
MaoLu937cf422017-03-03 23:31:46 -0800652 Map<ConnectPoint, ProtectedTransportEndpointState> map;
653 try {
MaoLu2846b112017-05-15 17:18:55 -0700654 map = behaviour.getProtectionEndpointStates().get();
MaoLu937cf422017-03-03 23:31:46 -0800655 } catch (InterruptedException e1) {
656 log.error("Interrupted.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700657 Thread.currentThread().interrupt();
658 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800659 } catch (ExecutionException e1) {
660 log.error("Exception caught.", e1);
MaoLu2846b112017-05-15 17:18:55 -0700661 return ImmutableMap.of();
MaoLu937cf422017-03-03 23:31:46 -0800662 }
663 return map;
664 }
665
Jimmy Yanda878fc2016-09-02 16:32:01 -0700666 // Listens to device events.
667 private class InternalDeviceListener implements DeviceListener {
668 @Override
669 public void event(DeviceEvent deviceEvent) {
670 Device device = deviceEvent.subject();
671
672 switch (deviceEvent.type()) {
673 case DEVICE_ADDED:
674 case DEVICE_UPDATED:
675 initDevice(device.id());
676 break;
677 case PORT_ADDED:
678 case PORT_UPDATED:
MaoLu937cf422017-03-03 23:31:46 -0800679 //FIXME
680 // As roadm application is a optional tool for now.
681 // The target power initialization will be enhanced later,
682 // hopefully using an formal optical subsystem.
683 // setInitialTargetPortPower(device.id(), deviceEvent.port().number());
Jimmy Yanda878fc2016-09-02 16:32:01 -0700684 break;
685 default:
686 break;
687
688 }
689 }
690 }
691}