/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.roadm; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Range; import org.onlab.osgi.ServiceDirectory; import org.onlab.util.Frequency; import org.onosproject.net.AnnotationKeys; import org.onosproject.net.DeviceId; import org.onosproject.net.device.DeviceService; import org.onosproject.net.OchSignal; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.ui.RequestHandler; import org.onosproject.ui.UiConnection; import org.onosproject.ui.UiMessageHandler; import org.onosproject.ui.table.TableModel; import org.onosproject.ui.table.TableRequestHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import static org.onosproject.net.Device.Type; /** * Table-View message handler for ROADM port view. */ public class RoadmPortViewMessageHandler extends UiMessageHandler { private static final String ROADM_PORT_DATA_REQ = "roadmPortDataRequest"; private static final String ROADM_PORT_DATA_RESP = "roadmPortDataResponse"; private static final String ROADM_PORTS = "roadmPorts"; private static final String ROADM_SET_TARGET_POWER_REQ = "roadmSetTargetPowerRequest"; private static final String ROADM_SET_TARGET_POWER_RESP = "roadmSetTargetPowerResponse"; private static final String ROADM_SHOW_ITEMS_REQ = "roadmShowPortItemsRequest"; private static final String ROADM_SHOW_ITEMS_RESP = "roadmShowPortItemsResponse"; private static final String ROADM_SET_OPS_MODE_REQ = "roadmSetOpsModeRequest"; private static final String ROADM_SET_OPS_MODE_RESP = "roadmSetOpsModeResponse"; private static final String ID = "id"; private static final String NAME = "name"; private static final String TYPE = "type"; private static final String ENABLED = "enabled"; private static final String MIN_FREQ = "minFreq"; private static final String MAX_FREQ = "maxFreq"; private static final String GRID = "grid"; private static final String POWER_RANGE = "powerRange"; private static final String CURRENT_POWER = "currentPower"; private static final String TARGET_POWER = "targetPower"; private static final String HAS_TARGET_POWER = "hasTargetPower"; private static final String SERVICE_STATE = "serviceState"; private static final String[] COLUMN_IDS = { ID, TYPE, NAME, ENABLED, MIN_FREQ, MAX_FREQ, GRID, POWER_RANGE, CURRENT_POWER, SERVICE_STATE, TARGET_POWER, HAS_TARGET_POWER }; private RoadmService roadmService; private DeviceService deviceService; private final Logger log = LoggerFactory.getLogger(getClass()); @Override public void init(UiConnection connection, ServiceDirectory directory) { super.init(connection, directory); roadmService = get(RoadmService.class); deviceService = get(DeviceService.class); } @Override protected Collection<RequestHandler> createRequestHandlers() { return ImmutableSet.of(new PortTableDataRequestHandler(), new SetTargetPowerRequestHandler(), new CreateShowItemsRequestHandler(), new CreateOpsModeSetRequestHandler() ); } // Handler for sample table requests private final class PortTableDataRequestHandler extends TableRequestHandler { private PortTableDataRequestHandler() { super(ROADM_PORT_DATA_REQ, ROADM_PORT_DATA_RESP, ROADM_PORTS); } @Override protected String[] getColumnIds() { return COLUMN_IDS; } @Override protected String noRowsMessage(ObjectNode payload) { return RoadmUtil.NO_ROWS_MESSAGE; } @Override protected void populateTable(TableModel tm, ObjectNode payload) { DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID)); if (deviceService.isAvailable(deviceId)) { List<Port> ports = deviceService.getPorts(deviceId); for (Port port : ports) { populateRow(tm.addRow(), port, deviceId); } } } private void populateRow(TableModel.Row row, Port port, DeviceId deviceId) { PortNumber portNum = port.number(); getFrequencyLimit(deviceId, portNum); row.cell(ID, portNum.toLong()) .cell(TYPE, port.type()) .cell(ENABLED, port.isEnabled()) .cell(NAME, RoadmUtil.getAnnotation(port.annotations(), AnnotationKeys.PORT_NAME)) .cell(MIN_FREQ, RoadmUtil.asTHz(minFreq)) .cell(MAX_FREQ, RoadmUtil.asTHz(maxFreq)) .cell(GRID, RoadmUtil.asGHz(channelSpacing)) .cell(POWER_RANGE, getPowerRange(deviceId, portNum)) .cell(CURRENT_POWER, getCurrentPower(deviceId, portNum)) .cell(SERVICE_STATE, getPortServiceState(deviceId, portNum)) .cell(TARGET_POWER, getTargetPower(deviceId, portNum)) .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, portNum)); } private String getPortServiceState(DeviceId deviceId, PortNumber portNumber) { return RoadmUtil.defaultString( roadmService.getProtectionSwitchPortState(deviceId, portNumber), RoadmUtil.UNKNOWN); } private Frequency minFreq = null, maxFreq = null, channelSpacing = null; // Gets min frequency, max frequency, channel spacing private void getFrequencyLimit(DeviceId deviceId, PortNumber portNumber) { Set<OchSignal> signals = roadmService.queryLambdas(deviceId, portNumber); if (signals.isEmpty()) { return; } Comparator<OchSignal> compare = (OchSignal a, OchSignal b) -> a.spacingMultiplier() - b.spacingMultiplier(); OchSignal minOch = Collections.min(signals, compare); OchSignal maxOch = Collections.max(signals, compare); minFreq = minOch.centralFrequency(); maxFreq = maxOch.centralFrequency(); channelSpacing = minOch.channelSpacing().frequency(); } // Returns the power range as a string, N/A if the power range not exists. // The power range would be input power range or target power range determined by port property. // If the port is RX direction then acquire the input power range from driver. // Otherwise there will be a TX direction port, thus acquire the target power range. private String getPowerRange(DeviceId deviceId, PortNumber portNumber) { Range<Long> range = roadmService.inputPortPowerRange(deviceId, portNumber); if (range == null) { range = roadmService.targetPortPowerRange(deviceId, portNumber); } return RoadmUtil.objectToString(range, RoadmUtil.NA); } // Returns the current power as a string, Unknown if no value can be found. private String getCurrentPower(DeviceId deviceId, PortNumber portNumber) { Long currentPower = roadmService.getCurrentPortPower(deviceId, portNumber); return RoadmUtil.objectToString(currentPower, RoadmUtil.UNKNOWN); } // Returns target power as a string, Unknown if target power is expected but // cannot be found, N/A if port does not have configurable target power private String getTargetPower(DeviceId deviceId, PortNumber portNumber) { if (!roadmService.hasPortTargetPower(deviceId, portNumber)) { return RoadmUtil.NA; } Long targetPower = roadmService.getTargetPortPower(deviceId, portNumber); return RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN); } } // Handler for setting port target power private final class SetTargetPowerRequestHandler extends RequestHandler { private static final String TARGET_POWER_ERR_MSG = "Target power range is %s."; private SetTargetPowerRequestHandler() { super(ROADM_SET_TARGET_POWER_REQ); } @Override public void process(ObjectNode payload) { DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID)); PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong()); Range<Long> range = roadmService.targetPortPowerRange(deviceId, portNumber); if (range == null) { log.warn("Unable to determine target power range for device {}", deviceId); return; } Long targetPower = payload.get(TARGET_POWER).asLong(); boolean validTargetPower = range.contains(targetPower); if (validTargetPower) { roadmService.setTargetPortPower(deviceId, portNumber, targetPower); } ObjectNode rootNode = objectNode(); rootNode.put(ID, payload.get(ID).asText()); rootNode.put(RoadmUtil.VALID, validTargetPower); rootNode.put(RoadmUtil.MESSAGE, String.format(TARGET_POWER_ERR_MSG, range.toString())); sendMessage(ROADM_SET_TARGET_POWER_RESP, rootNode); } } private final class CreateShowItemsRequestHandler extends RequestHandler { private static final String SHOW_TARGET_POWER = "showTargetPower"; private static final String SHOW_SERVICE_STATE = "showServiceState"; private static final String SHOW_FLOW_ICON = "showFlowIcon"; private CreateShowItemsRequestHandler() { super(ROADM_SHOW_ITEMS_REQ); } @Override public void process(ObjectNode payload) { DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID)); Type devType = deviceService.getDevice(did).type(); // Build response ObjectNode node = objectNode(); node.put(SHOW_TARGET_POWER, devType != Type.FIBER_SWITCH); node.put(SHOW_SERVICE_STATE, devType == Type.FIBER_SWITCH); node.put(SHOW_FLOW_ICON, devType == Type.ROADM); sendMessage(ROADM_SHOW_ITEMS_RESP, node); } } private final class CreateOpsModeSetRequestHandler extends RequestHandler { private static final String OPS_SWITCH_INDEX = "index"; private static final String DEVICE_INVALID_ERR_MSG = "Apply failed: device is offline or unavailable."; private static final String TYPE_INVALID_ERR_MSG = "Apply failed: invalid device type."; private CreateOpsModeSetRequestHandler() { super(ROADM_SET_OPS_MODE_REQ); } @Override public void process(ObjectNode payload) { DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID)); ObjectNode node = objectNode(); if (!deviceService.isAvailable(did)) { node.put(RoadmUtil.VALID, false); node.put(RoadmUtil.MESSAGE, DEVICE_INVALID_ERR_MSG); sendMessage(ROADM_SET_OPS_MODE_RESP, node); return; } Type devType = deviceService.getDevice(did).type(); if (devType != Type.FIBER_SWITCH) { node.put(RoadmUtil.VALID, false); node.put(RoadmUtil.MESSAGE, TYPE_INVALID_ERR_MSG); sendMessage(ROADM_SET_OPS_MODE_RESP, node); return; } // get virtual port and switch port from payload roadmService.setProtectionSwitchWorkingPath(did, (int) number(payload, OPS_SWITCH_INDEX)); node.put(RoadmUtil.VALID, true); sendMessage(ROADM_SET_OPS_MODE_RESP, node); } } }