Andrea Campanella | e1e3e44 | 2019-10-21 13:45:32 +0200 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2018-present Open Networking Foundation |
| 3 | * |
| 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 | */ |
| 16 | |
| 17 | package org.onosproject.odtn.impl; |
| 18 | |
| 19 | import com.fasterxml.jackson.core.JsonEncoding; |
| 20 | import com.fasterxml.jackson.core.JsonFactory; |
| 21 | import com.fasterxml.jackson.core.JsonGenerator; |
| 22 | import com.fasterxml.jackson.databind.JsonNode; |
| 23 | import com.fasterxml.jackson.databind.ObjectMapper; |
| 24 | import com.fasterxml.jackson.databind.ObjectReader; |
| 25 | import com.google.common.annotations.Beta; |
| 26 | import org.apache.commons.lang3.tuple.Pair; |
| 27 | import org.onlab.graph.ScalarWeight; |
| 28 | import org.onosproject.core.ApplicationId; |
| 29 | import org.onosproject.core.CoreService; |
| 30 | import org.onosproject.net.ChannelSpacing; |
| 31 | import org.onosproject.net.ConnectPoint; |
| 32 | import org.onosproject.net.DefaultPath; |
| 33 | import org.onosproject.net.Device; |
| 34 | import org.onosproject.net.DeviceId; |
| 35 | import org.onosproject.net.Direction; |
| 36 | import org.onosproject.net.GridType; |
| 37 | import org.onosproject.net.Link; |
| 38 | import org.onosproject.net.OchSignal; |
| 39 | import org.onosproject.net.Path; |
| 40 | import org.onosproject.net.behaviour.PowerConfig; |
| 41 | import org.onosproject.net.device.DeviceService; |
| 42 | import org.onosproject.net.intent.Intent; |
| 43 | import org.onosproject.net.intent.IntentEvent; |
| 44 | import org.onosproject.net.intent.IntentId; |
| 45 | import org.onosproject.net.intent.IntentListener; |
| 46 | import org.onosproject.net.intent.IntentService; |
| 47 | import org.onosproject.net.link.LinkService; |
| 48 | import org.onosproject.net.provider.ProviderId; |
| 49 | import org.onosproject.odtn.GnpyService; |
| 50 | import org.onosproject.store.service.AtomicCounter; |
| 51 | import org.onosproject.store.service.StorageService; |
| 52 | import org.osgi.service.component.annotations.Activate; |
| 53 | import org.osgi.service.component.annotations.Component; |
| 54 | import org.osgi.service.component.annotations.Reference; |
| 55 | import org.osgi.service.component.annotations.ReferenceCardinality; |
| 56 | import org.slf4j.Logger; |
| 57 | import org.slf4j.LoggerFactory; |
| 58 | |
| 59 | import javax.ws.rs.core.MediaType; |
| 60 | import java.io.ByteArrayInputStream; |
| 61 | import java.io.ByteArrayOutputStream; |
| 62 | import java.io.IOException; |
| 63 | import java.util.ArrayList; |
| 64 | import java.util.HashMap; |
| 65 | import java.util.Iterator; |
| 66 | import java.util.List; |
| 67 | import java.util.Map; |
| 68 | import java.util.Set; |
| 69 | import java.util.stream.Collectors; |
| 70 | import java.util.stream.StreamSupport; |
| 71 | |
| 72 | import static java.lang.Math.log10; |
| 73 | import static org.onosproject.net.ChannelSpacing.CHL_50GHZ; |
| 74 | import static org.onosproject.net.ChannelSpacing.CHL_6P25GHZ; |
| 75 | import static org.onosproject.net.optical.util.OpticalIntentUtility.createOpticalIntent; |
| 76 | |
| 77 | /** |
| 78 | * Implementation of GnpyService. |
| 79 | */ |
| 80 | @Beta |
| 81 | @Component(immediate = true, service = GnpyService.class) |
| 82 | public class GnpyManager implements GnpyService { |
| 83 | |
| 84 | private final Logger log = LoggerFactory.getLogger(getClass()); |
| 85 | |
| 86 | @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| 87 | protected IntentService intentService; |
| 88 | |
| 89 | @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| 90 | protected DeviceService deviceService; |
| 91 | |
| 92 | @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| 93 | protected CoreService coreService; |
| 94 | |
| 95 | @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| 96 | protected LinkService linkService; |
| 97 | |
| 98 | @Reference(cardinality = ReferenceCardinality.MANDATORY) |
| 99 | protected StorageService storageService; |
| 100 | |
| 101 | HttpUtil gnpyHttpUtil; |
| 102 | |
| 103 | private static final String APP_ID = "org.onosproject.odtn-service"; |
| 104 | |
| 105 | private static final ProviderId PROVIDER_ID = new ProviderId("odtn", "gnpy"); |
| 106 | |
| 107 | private ApplicationId appId; |
| 108 | |
| 109 | private AtomicCounter counter; |
| 110 | |
| 111 | private Map<IntentId, GnpyPowerInfo> intentsPowerMap = new HashMap<>(); |
| 112 | |
| 113 | @Activate |
| 114 | protected void activate() { |
| 115 | log.info("Started"); |
| 116 | appId = coreService.getAppId(APP_ID); |
| 117 | counter = storageService.getAtomicCounter("GNPy-connection-counter"); |
| 118 | } |
| 119 | |
| 120 | |
| 121 | @Override |
| 122 | public boolean connectGnpy(String protocol, String ip, String port, String username, String password) { |
| 123 | gnpyHttpUtil = new HttpUtil(protocol, ip, port); |
| 124 | gnpyHttpUtil.connect(username, password); |
| 125 | return gnpyHttpUtil.get("/gnpy-experimental", MediaType.APPLICATION_JSON_TYPE) != null; |
| 126 | } |
| 127 | |
| 128 | @Override |
| 129 | public boolean disconnectGnpy() { |
| 130 | gnpyHttpUtil.disconnect(); |
| 131 | gnpyHttpUtil = null; |
| 132 | return true; |
| 133 | } |
| 134 | |
| 135 | @Override |
| 136 | public boolean isConnected() { |
| 137 | return gnpyHttpUtil != null; |
| 138 | } |
| 139 | |
| 140 | @Override |
| 141 | public Pair<IntentId, Double> obtainConnectivity(ConnectPoint ingress, ConnectPoint egress, boolean bidirectional) { |
| 142 | ByteArrayOutputStream connectivityRequest = createGnpyRequest(ingress, egress, bidirectional); |
| 143 | String response = gnpyHttpUtil.post(null, "/gnpy-experimental", |
| 144 | new ByteArrayInputStream(connectivityRequest.toByteArray()), |
| 145 | MediaType.APPLICATION_JSON_TYPE, String.class); |
| 146 | ObjectMapper om = new ObjectMapper(); |
| 147 | final ObjectReader reader = om.reader(); |
| 148 | JsonNode jsonNode; |
| 149 | try { |
| 150 | jsonNode = reader.readTree(response); |
| 151 | if (jsonNode == null) { |
| 152 | log.error("JsonNode is null for response {}", response); |
| 153 | return null; |
| 154 | } |
| 155 | log.info("Response {}", response); |
| 156 | String bestPath; |
| 157 | try { |
| 158 | bestPath = getBestOsnrPathKey(jsonNode); |
| 159 | } catch (IllegalStateException e) { |
| 160 | log.error("Exception while contacting GNPy", e); |
| 161 | return null; |
| 162 | } |
| 163 | OchSignal ochSignal = createOchSignal(jsonNode); |
| 164 | Map<DeviceId, Double> deviceAtoBPowerMap = new HashMap<>(); |
| 165 | Map<DeviceId, Double> deviceBtoAPowerMap = new HashMap<>(); |
| 166 | //TODO this list is currently only populated in the forward direction |
| 167 | List<DeviceId> deviceIds = getDeviceAndPopulatePowerMap(jsonNode, deviceAtoBPowerMap, |
| 168 | deviceBtoAPowerMap, bestPath); |
| 169 | Path suggestedPath = createSuggestedPath(deviceIds); |
| 170 | log.info("Suggested path {}", suggestedPath); |
| 171 | |
| 172 | Intent intent = createOpticalIntent(ingress, egress, deviceService, |
| 173 | null, appId, bidirectional, ochSignal, suggestedPath); |
| 174 | |
| 175 | intentsPowerMap.put(intent.id(), new GnpyPowerInfo(deviceAtoBPowerMap, deviceBtoAPowerMap, |
| 176 | getLaunchPower(jsonNode), suggestedPath.links(), |
| 177 | ingress, egress, ochSignal)); |
| 178 | intentService.submit(intent); |
| 179 | return Pair.of(intent.id(), getOsnr(jsonNode, bestPath)); |
| 180 | } catch (IOException e) { |
| 181 | log.error("Exception while reading response {}", response, e); |
| 182 | return null; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | private String getBestOsnrPathKey(JsonNode connectivityReply) throws IllegalStateException { |
| 187 | Double bestOsnr = -100.0; |
| 188 | String bestPathId = ""; |
| 189 | if (connectivityReply.get("result").asText().contains("Service error")) { |
| 190 | throw new IllegalStateException(connectivityReply.get("result").asText()); |
| 191 | } |
| 192 | Iterator<JsonNode> paths = connectivityReply.get("result").get("response") |
| 193 | .elements(); |
| 194 | while (paths.hasNext()) { |
| 195 | JsonNode path = paths.next(); |
| 196 | String respId = path.get("response-id").asText(); |
| 197 | double osnr = getOsnr(connectivityReply, respId); |
| 198 | if (osnr > bestOsnr) { |
| 199 | bestOsnr = osnr; |
| 200 | bestPathId = respId; |
| 201 | } |
| 202 | } |
| 203 | return bestPathId; |
| 204 | } |
| 205 | |
| 206 | protected Path createSuggestedPath(List<DeviceId> deviceIds) { |
| 207 | List<Link> listLinks = new ArrayList<>(); |
| 208 | for (int i = 0; i < deviceIds.size() - 1; i++) { |
| 209 | Set<Link> links = linkService.getDeviceLinks(deviceIds.get(i)); |
| 210 | |
| 211 | for (Link link : links) { |
| 212 | if (link.dst().deviceId().equals(deviceIds.get(i + 1))) { |
| 213 | listLinks.add(link); |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | return new DefaultPath(PROVIDER_ID, listLinks, new ScalarWeight(1)); |
| 218 | |
| 219 | } |
| 220 | |
| 221 | protected List<DeviceId> getDeviceAndPopulatePowerMap(JsonNode connectivityReply, |
| 222 | Map<DeviceId, Double> deviceAtoBPowerMap, |
| 223 | Map<DeviceId, Double> deviceBtoAPowerMap, |
| 224 | String name) { |
| 225 | List<DeviceId> deviceIds = new ArrayList<>(); |
| 226 | if (connectivityReply.has("result") |
| 227 | && connectivityReply.get("result").has("response")) { |
| 228 | JsonNode response = connectivityReply.get("result").get("response"); |
| 229 | //getting the a-b path. |
| 230 | Iterator<JsonNode> paths = connectivityReply.get("result").get("response") |
| 231 | .elements(); |
| 232 | while (paths.hasNext()) { |
| 233 | JsonNode path = paths.next(); |
| 234 | if (path.get("response-id").asText().equals(name)) { |
| 235 | Iterator<JsonNode> elements = path.get("path-properties") |
| 236 | .get("reversed-path-route-objects").elements(); |
| 237 | Iterable<JsonNode> iterable = () -> elements; |
| 238 | List<JsonNode> elementsList = StreamSupport |
| 239 | .stream(iterable.spliterator(), false) |
| 240 | .collect(Collectors.toList()); |
| 241 | Iterator<JsonNode> reversePathRoute = path.get("path-properties") |
| 242 | .get("reversed-path-route-objects").elements(); |
| 243 | Iterable<JsonNode> reversedIterable = () -> reversePathRoute; |
| 244 | List<JsonNode> reversedElementsList = StreamSupport |
| 245 | .stream(reversedIterable.spliterator(), false) |
| 246 | .collect(Collectors.toList()); |
| 247 | for (int i = 0; i < elementsList.size() - 1; i++) { |
| 248 | if (elementsList.get(i).get("path-route-object").has("num-unnum-hop")) { |
| 249 | String elementId = elementsList.get(i).get("path-route-object") |
| 250 | .get("num-unnum-hop").get("node-id") |
| 251 | .asText(); |
| 252 | //TODO this is a workaround until we understand better the |
| 253 | // topology mapping between ONOS and GNPy |
| 254 | if (elementId.startsWith("netconf:")) { |
| 255 | double power = -99; |
| 256 | if (!elementsList.get(i).get("path-route-object") |
| 257 | .get("num-unnum-hop").get("gnpy-node-type") |
| 258 | .asText().equals("transceiver")) { |
| 259 | power = getPerHopPower(elementsList.get(i + 2)); |
| 260 | } |
| 261 | deviceAtoBPowerMap.put(DeviceId.deviceId(elementId), power); |
| 262 | for (int j = 0; j < reversedElementsList.size() - 1; j++) { |
| 263 | if (reversedElementsList.get(j).get("path-route-object").has("num-unnum-hop")) { |
| 264 | String reversedElementId = reversedElementsList.get(j).get("path-route-object") |
| 265 | .get("num-unnum-hop").get("node-id") |
| 266 | .asText(); |
| 267 | double reversePower = -99; |
| 268 | if (reversedElementId.equals(elementId)) { |
| 269 | reversePower = getPerHopPower(reversedElementsList.get(j + 2)); |
| 270 | deviceBtoAPowerMap.put(DeviceId.deviceId(elementId), reversePower); |
| 271 | } |
| 272 | } |
| 273 | } |
| 274 | deviceIds.add(DeviceId.deviceId(elementId)); |
| 275 | } |
| 276 | } |
| 277 | } |
| 278 | break; |
| 279 | } |
| 280 | } |
| 281 | } else { |
| 282 | log.warn("Can't retrieve devices {}", connectivityReply); |
| 283 | } |
| 284 | return deviceIds; |
| 285 | } |
| 286 | |
| 287 | protected OchSignal createOchSignal(JsonNode connectivityReply) throws IllegalArgumentException { |
| 288 | if (connectivityReply.has("result") |
| 289 | && connectivityReply.get("result").has("response")) { |
| 290 | Iterator<JsonNode> elements = connectivityReply.get("result").get("response").elements() |
| 291 | .next().get("path-properties").get("path-route-objects").elements(); |
| 292 | Iterable<JsonNode> iterable = () -> elements; |
| 293 | List<JsonNode> elementsList = StreamSupport |
| 294 | .stream(iterable.spliterator(), false) |
| 295 | .collect(Collectors.toList()); |
| 296 | int n = 0; |
| 297 | int m = 0; |
| 298 | for (JsonNode node : elementsList) { |
| 299 | if (node.get("path-route-object").has("label-hop")) { |
| 300 | n = node.get("path-route-object").get("label-hop").get("N").asInt(); |
| 301 | m = node.get("path-route-object").get("label-hop").get("M").asInt(); |
| 302 | break; |
| 303 | } |
| 304 | } |
| 305 | int offset = 193100; |
| 306 | |
| 307 | double centralFreq = offset + (n * CHL_6P25GHZ.frequency().asGHz()); |
| 308 | try { |
| 309 | int multiplier = getMultplier(centralFreq, GridType.DWDM, CHL_50GHZ); |
| 310 | return new OchSignal(GridType.DWDM, CHL_50GHZ, multiplier, 4); |
| 311 | } catch (RuntimeException e) { |
| 312 | /* catching RuntimeException as both NullPointerException (thrown by |
| 313 | * checkNotNull) and IllegalArgumentException (thrown by checkArgument) |
| 314 | * are subclasses of RuntimeException. |
| 315 | */ |
| 316 | throw new IllegalArgumentException(e); |
| 317 | } |
| 318 | } |
| 319 | return null; |
| 320 | } |
| 321 | |
| 322 | protected double getLaunchPower(JsonNode connectivityReply) { |
| 323 | double power = -99; |
| 324 | if (connectivityReply.has("result") |
| 325 | && connectivityReply.get("result").has("response")) { |
| 326 | Iterator<JsonNode> elements = connectivityReply.get("result").get("response") |
| 327 | .elements().next().get("path-properties").get("path-metric").elements(); |
| 328 | Iterable<JsonNode> iterable = () -> elements; |
| 329 | List<JsonNode> elementsList = StreamSupport |
| 330 | .stream(iterable.spliterator(), false) |
| 331 | .collect(Collectors.toList()); |
| 332 | for (JsonNode node : elementsList) { |
| 333 | if (node.has("metric-type") && |
| 334 | node.get("metric-type").asText().equals("reference_power")) { |
| 335 | power = node.get("accumulative-value").asDouble(); |
| 336 | break; |
| 337 | } |
| 338 | } |
| 339 | } |
| 340 | return 10 * log10(power * 1000); |
| 341 | } |
| 342 | |
| 343 | protected double getPerHopPower(JsonNode pathRouteObj) { |
| 344 | double power = -99; |
| 345 | if (pathRouteObj.get("path-route-object").has("target-channel-power")) { |
| 346 | power = pathRouteObj.get("path-route-object") |
| 347 | .get("target-channel-power").get("value") |
| 348 | .asDouble(); |
| 349 | } |
| 350 | return power; |
| 351 | } |
| 352 | |
| 353 | protected double getOsnr(JsonNode connectivityReply, String name) { |
| 354 | double osnr = -1; |
| 355 | if (connectivityReply.has("result") |
| 356 | && connectivityReply.get("result").has("response")) { |
| 357 | Iterator<JsonNode> paths = connectivityReply.get("result").get("response") |
| 358 | .elements(); |
| 359 | while (paths.hasNext()) { |
| 360 | JsonNode path = paths.next(); |
| 361 | if (path.get("response-id").asText().equals(name)) { |
| 362 | Iterator<JsonNode> elements = path.get("path-properties").get("path-metric").elements(); |
| 363 | Iterable<JsonNode> iterable = () -> elements; |
| 364 | List<JsonNode> elementsList = StreamSupport |
| 365 | .stream(iterable.spliterator(), false) |
| 366 | .collect(Collectors.toList()); |
| 367 | for (JsonNode node : elementsList) { |
| 368 | if (node.has("metric-type") && |
| 369 | node.get("metric-type").asText().equals("OSNR-0.1nm")) { |
| 370 | osnr = node.get("accumulative-value").asDouble(); |
| 371 | break; |
| 372 | } |
| 373 | } |
| 374 | if (osnr != -1) { |
| 375 | break; |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | } |
| 380 | return osnr; |
| 381 | } |
| 382 | |
| 383 | private int getMultplier(double wavelength, GridType gridType, ChannelSpacing channelSpacing) { |
| 384 | long baseFreq; |
| 385 | switch (gridType) { |
| 386 | case DWDM: |
| 387 | baseFreq = 193100; |
| 388 | break; |
| 389 | case CWDM: |
| 390 | case FLEX: |
| 391 | case UNKNOWN: |
| 392 | default: |
| 393 | baseFreq = 0L; |
| 394 | break; |
| 395 | } |
| 396 | return (int) ((wavelength - baseFreq) / (channelSpacing.frequency().asGHz())); |
| 397 | } |
| 398 | |
| 399 | protected ByteArrayOutputStream createGnpyRequest(ConnectPoint ingress, |
| 400 | ConnectPoint egress, boolean bidirectional) { |
| 401 | /* |
| 402 | { |
| 403 | "path-request": [ |
| 404 | { |
| 405 | "request-id": "first", |
| 406 | "source": "trx-Amsterdam", |
| 407 | "destination": "trx-Bremen", |
| 408 | "src-tp-id": "trx-Amsterdam", |
| 409 | "dst-tp-id": "trx-Bremen", |
| 410 | "bidirectional": false, |
| 411 | "path-constraints": { |
| 412 | "te-bandwidth": { |
| 413 | "technology": "flexi-grid", |
| 414 | "trx_type": "Voyager", |
| 415 | "trx_mode": null, |
| 416 | "effective-freq-slot": [ |
| 417 | { |
| 418 | "N": "null", |
| 419 | "M": "null" |
| 420 | } |
| 421 | ], |
| 422 | "spacing": 50000000000.0, |
| 423 | "max-nb-of-channel": null, |
| 424 | "output-power": null, |
| 425 | "path_bandwidth": 100000000000.0 |
| 426 | } |
| 427 | } |
| 428 | } |
| 429 | ] |
| 430 | } |
| 431 | */ |
| 432 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
| 433 | try { |
| 434 | JsonGenerator generator = getJsonGenerator(stream); |
| 435 | generator.writeStartObject(); |
| 436 | generator.writeArrayFieldStart("path-request"); |
| 437 | generator.writeStartObject(); |
| 438 | generator.writeStringField("request-id", "onos-" + counter.getAndIncrement()); |
| 439 | generator.writeStringField("source", ingress.deviceId().toString()); |
| 440 | generator.writeStringField("destination", egress.deviceId().toString()); |
| 441 | generator.writeStringField("src-tp-id", ingress.deviceId().toString()); |
| 442 | generator.writeStringField("dst-tp-id", egress.deviceId().toString()); |
| 443 | generator.writeBooleanField("bidirectional", bidirectional); |
| 444 | generator.writeObjectFieldStart("path-constraints"); |
| 445 | generator.writeObjectFieldStart("te-bandwidth"); |
| 446 | generator.writeStringField("technology", "flexi-grid"); |
| 447 | generator.writeStringField("trx_type", "Cassini"); //TODO make variable |
| 448 | generator.writeNullField("trx_mode"); |
| 449 | generator.writeArrayFieldStart("effective-freq-slot"); |
| 450 | generator.writeStartObject(); |
| 451 | generator.writeStringField("N", "null"); |
| 452 | generator.writeStringField("M", "null"); |
| 453 | generator.writeEndObject(); |
| 454 | generator.writeEndArray(); |
| 455 | generator.writeNumberField("spacing", 50000000000.0); |
| 456 | generator.writeNullField("max-nb-of-channel"); |
| 457 | generator.writeNullField("output-power"); |
| 458 | generator.writeNumberField("path_bandwidth", 100000000000.0); |
| 459 | generator.writeEndObject(); |
| 460 | generator.writeEndObject(); |
| 461 | generator.writeEndObject(); |
| 462 | generator.writeEndArray(); |
| 463 | generator.writeEndObject(); |
| 464 | generator.close(); |
| 465 | return stream; |
| 466 | } catch (IOException e) { |
| 467 | log.error("Cant' create json", e); |
| 468 | } |
| 469 | return stream; |
| 470 | |
| 471 | } |
| 472 | |
| 473 | private JsonGenerator getJsonGenerator(ByteArrayOutputStream stream) throws IOException { |
| 474 | JsonFactory factory = new JsonFactory(); |
| 475 | return factory.createGenerator(stream, JsonEncoding.UTF8); |
| 476 | } |
| 477 | |
| 478 | /** |
| 479 | * Internal listener for tracking the intent deletion events. |
| 480 | */ |
| 481 | private class InternalIntentListener implements IntentListener { |
| 482 | |
| 483 | @Override |
| 484 | public boolean isRelevant(IntentEvent event) { |
| 485 | return intentsPowerMap.keySet().contains(event.subject().id()); |
| 486 | } |
| 487 | |
| 488 | @Override |
| 489 | public void event(IntentEvent event) { |
| 490 | setPathPower(event.subject()); |
| 491 | |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | private void setPathPower(Intent intent) { |
| 496 | GnpyPowerInfo powerInfo = intentsPowerMap.get(intent.id()); |
| 497 | for (Link link : powerInfo.path()) { |
| 498 | Device ingressDev = deviceService.getDevice(link.src().deviceId()); |
| 499 | if (ingressDev.is(PowerConfig.class)) { |
| 500 | if (powerInfo.deviceAtoBPowerMap().get(link.src().deviceId()) != -99) { |
| 501 | log.info("Configuring power {} for {}", |
| 502 | powerInfo.deviceAtoBPowerMap().get(link.src().deviceId()), |
| 503 | link.src().deviceId()); |
| 504 | ingressDev.as(PowerConfig.class) |
| 505 | .setTargetPower(link.src().port(), powerInfo.ochSignal(), |
| 506 | powerInfo.deviceAtoBPowerMap() |
| 507 | .get(link.src().deviceId())); |
| 508 | } else { |
| 509 | log.warn("Can't determine power for {}", link.src().deviceId()); |
| 510 | } |
| 511 | } |
| 512 | Device egressDev = deviceService.getDevice(link.dst().deviceId()); |
| 513 | if (egressDev.is(PowerConfig.class)) { |
| 514 | if (powerInfo.deviceBtoAPowerMap().get(link.dst().deviceId()) != -99) { |
| 515 | log.info("Configuring power {} for {}", |
| 516 | powerInfo.deviceBtoAPowerMap().get(link.dst().deviceId()), |
| 517 | link.dst().deviceId()); |
| 518 | egressDev.as(PowerConfig.class) |
| 519 | .setTargetPower(link.dst().port(), powerInfo.ochSignal(), |
| 520 | powerInfo.deviceBtoAPowerMap() |
| 521 | .get(link.dst().deviceId())); |
| 522 | } else { |
| 523 | log.warn("Can't determine power for {}", link.dst().deviceId()); |
| 524 | } |
| 525 | } |
| 526 | } |
| 527 | Device ingressDevice = deviceService.getDevice(powerInfo.ingress().deviceId()); |
| 528 | if (ingressDevice.is(PowerConfig.class)) { |
| 529 | if (powerInfo.launchPower() != -99) { |
| 530 | log.info("Configuring ingress with power {} for {}", |
| 531 | powerInfo.launchPower(), ingressDevice); |
| 532 | ingressDevice.as(PowerConfig.class) |
| 533 | .setTargetPower(powerInfo.ingress().port(), Direction.ALL, powerInfo.launchPower()); |
| 534 | } |
| 535 | } |
| 536 | Device egressDevice = deviceService.getDevice(powerInfo.ingress().deviceId()); |
| 537 | if (egressDevice.is(PowerConfig.class)) { |
| 538 | if (powerInfo.launchPower() != -99) { |
| 539 | log.info("Configuring egress with power {} for {}", |
| 540 | powerInfo.launchPower(), ingressDevice); |
| 541 | ingressDevice.as(PowerConfig.class) |
| 542 | .setTargetPower(powerInfo.ingress().port(), Direction.ALL, powerInfo.launchPower()); |
| 543 | } |
| 544 | } |
| 545 | } |
| 546 | } |