blob: dea83b01aff4bc218b6aa02b10f9b8031db47c49 [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.fasterxml.jackson.databind.node.ArrayNode;
19import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Jimmy Yanda878fc2016-09-02 16:32:01 -070020import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Range;
23import org.onlab.osgi.ServiceDirectory;
MaoLu937cf422017-03-03 23:31:46 -080024import org.onlab.util.Frequency;
Jimmy Yanda878fc2016-09-02 16:32:01 -070025import org.onosproject.net.AnnotationKeys;
MaoLu2846b112017-05-15 17:18:55 -070026import org.onosproject.net.ConnectPoint;
Jimmy Yanda878fc2016-09-02 16:32:01 -070027import org.onosproject.net.DeviceId;
MaoLu2846b112017-05-15 17:18:55 -070028import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
29import org.onosproject.net.behaviour.protection.TransportEndpointState;
MaoLu937cf422017-03-03 23:31:46 -080030import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.OchSignal;
Jimmy Yanda878fc2016-09-02 16:32:01 -070032import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
alessiod4a2b842019-04-30 18:43:17 +020034import org.onosproject.net.intent.OpticalPathIntent;
MaoLu2846b112017-05-15 17:18:55 -070035import org.onosproject.net.optical.OpticalAnnotations;
Jimmy Yanda878fc2016-09-02 16:32:01 -070036import org.onosproject.ui.RequestHandler;
37import org.onosproject.ui.UiConnection;
38import org.onosproject.ui.UiMessageHandler;
39import org.onosproject.ui.table.TableModel;
40import org.onosproject.ui.table.TableRequestHandler;
41import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
44import java.util.Collection;
MaoLu937cf422017-03-03 23:31:46 -080045import java.util.Collections;
46import java.util.Comparator;
Jimmy Yanda878fc2016-09-02 16:32:01 -070047import java.util.List;
MaoLu2846b112017-05-15 17:18:55 -070048import java.util.Map;
MaoLu937cf422017-03-03 23:31:46 -080049import java.util.Set;
50
51import static org.onosproject.net.Device.Type;
MaoLu2846b112017-05-15 17:18:55 -070052import static org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState.ACTIVE_UNKNOWN;
53import static org.onosproject.roadm.RoadmUtil.OPS_OPT_AUTO;
54import static org.onosproject.roadm.RoadmUtil.OPS_OPT_FORCE;
55import static org.onosproject.roadm.RoadmUtil.OPS_OPT_MANUAL;
Jimmy Yanda878fc2016-09-02 16:32:01 -070056
57/**
58 * Table-View message handler for ROADM port view.
59 */
60public class RoadmPortViewMessageHandler extends UiMessageHandler {
61
62 private static final String ROADM_PORT_DATA_REQ = "roadmPortDataRequest";
63 private static final String ROADM_PORT_DATA_RESP = "roadmPortDataResponse";
64 private static final String ROADM_PORTS = "roadmPorts";
Jimmy Yanda878fc2016-09-02 16:32:01 -070065 private static final String ROADM_SET_TARGET_POWER_REQ = "roadmSetTargetPowerRequest";
66 private static final String ROADM_SET_TARGET_POWER_RESP = "roadmSetTargetPowerResponse";
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -070067 private static final String ROADM_SYNC_TARGET_POWER_REQ = "roadmSyncTargetPowerRequest";
68 private static final String ROADM_SYNC_TARGET_POWER_RESP = "roadmSyncTargetPowerResp";
MaoLu937cf422017-03-03 23:31:46 -080069 private static final String ROADM_SHOW_ITEMS_REQ = "roadmShowPortItemsRequest";
70 private static final String ROADM_SHOW_ITEMS_RESP = "roadmShowPortItemsResponse";
71 private static final String ROADM_SET_OPS_MODE_REQ = "roadmSetOpsModeRequest";
72 private static final String ROADM_SET_OPS_MODE_RESP = "roadmSetOpsModeResponse";
Jimmy Yanda878fc2016-09-02 16:32:01 -070073
74 private static final String ID = "id";
alessiod4a2b842019-04-30 18:43:17 +020075 private static final String REVERSE_PORT = "reversePort";
Jimmy Yanda878fc2016-09-02 16:32:01 -070076 private static final String NAME = "name";
MaoLu937cf422017-03-03 23:31:46 -080077 private static final String TYPE = "type";
Jimmy Yanda878fc2016-09-02 16:32:01 -070078 private static final String ENABLED = "enabled";
79 private static final String MIN_FREQ = "minFreq";
80 private static final String MAX_FREQ = "maxFreq";
81 private static final String GRID = "grid";
MaoLu2f7eadb2017-05-02 15:38:43 -070082 private static final String POWER_RANGE = "powerRange";
Jimmy Yanda878fc2016-09-02 16:32:01 -070083 private static final String CURRENT_POWER = "currentPower";
84 private static final String TARGET_POWER = "targetPower";
85 private static final String HAS_TARGET_POWER = "hasTargetPower";
MaoLu937cf422017-03-03 23:31:46 -080086 private static final String SERVICE_STATE = "serviceState";
Jimmy Yanda878fc2016-09-02 16:32:01 -070087
88 private static final String[] COLUMN_IDS = {
alessiod4a2b842019-04-30 18:43:17 +020089 ID, REVERSE_PORT, TYPE, NAME, ENABLED, MIN_FREQ, MAX_FREQ, GRID, POWER_RANGE,
MaoLu937cf422017-03-03 23:31:46 -080090 CURRENT_POWER, SERVICE_STATE, TARGET_POWER, HAS_TARGET_POWER
Jimmy Yanda878fc2016-09-02 16:32:01 -070091 };
92
Jimmy Yanda878fc2016-09-02 16:32:01 -070093 private RoadmService roadmService;
MaoLu937cf422017-03-03 23:31:46 -080094 private DeviceService deviceService;
Jimmy Yanda878fc2016-09-02 16:32:01 -070095
96 private final Logger log = LoggerFactory.getLogger(getClass());
97
98 @Override
99 public void init(UiConnection connection, ServiceDirectory directory) {
100 super.init(connection, directory);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700101 roadmService = get(RoadmService.class);
MaoLu937cf422017-03-03 23:31:46 -0800102 deviceService = get(DeviceService.class);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700103 }
104
105 @Override
106 protected Collection<RequestHandler> createRequestHandlers() {
MaoLu937cf422017-03-03 23:31:46 -0800107 return ImmutableSet.of(new PortTableDataRequestHandler(),
108 new SetTargetPowerRequestHandler(),
109 new CreateShowItemsRequestHandler(),
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700110 new CreateOpsModeSetRequestHandler(),
111 new SyncTargetPowerRequestHandler()
MaoLu937cf422017-03-03 23:31:46 -0800112 );
Jimmy Yanda878fc2016-09-02 16:32:01 -0700113 }
114
115 // Handler for sample table requests
116 private final class PortTableDataRequestHandler extends TableRequestHandler {
117
118 private PortTableDataRequestHandler() {
119 super(ROADM_PORT_DATA_REQ, ROADM_PORT_DATA_RESP, ROADM_PORTS);
120 }
121
122 @Override
123 protected String[] getColumnIds() {
124 return COLUMN_IDS;
125 }
126
127 @Override
128 protected String noRowsMessage(ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800129 return RoadmUtil.NO_ROWS_MESSAGE;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700130 }
131
132 @Override
133 protected void populateTable(TableModel tm, ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800134 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
Jimmy Yanda878fc2016-09-02 16:32:01 -0700135 if (deviceService.isAvailable(deviceId)) {
136 List<Port> ports = deviceService.getPorts(deviceId);
137 for (Port port : ports) {
138 populateRow(tm.addRow(), port, deviceId);
139 }
140 }
141 }
142
143 private void populateRow(TableModel.Row row, Port port, DeviceId deviceId) {
MaoLu937cf422017-03-03 23:31:46 -0800144 PortNumber portNum = port.number();
145 getFrequencyLimit(deviceId, portNum);
146 row.cell(ID, portNum.toLong())
alessiod4a2b842019-04-30 18:43:17 +0200147 .cell(REVERSE_PORT, RoadmUtil.getAnnotation(port.annotations(),
148 OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY))
Jimmy Yanda878fc2016-09-02 16:32:01 -0700149 .cell(TYPE, port.type())
150 .cell(ENABLED, port.isEnabled())
MaoLu937cf422017-03-03 23:31:46 -0800151 .cell(NAME, RoadmUtil.getAnnotation(port.annotations(), AnnotationKeys.PORT_NAME))
152 .cell(MIN_FREQ, RoadmUtil.asTHz(minFreq))
153 .cell(MAX_FREQ, RoadmUtil.asTHz(maxFreq))
154 .cell(GRID, RoadmUtil.asGHz(channelSpacing))
MaoLu2f7eadb2017-05-02 15:38:43 -0700155 .cell(POWER_RANGE, getPowerRange(deviceId, portNum))
MaoLu937cf422017-03-03 23:31:46 -0800156 .cell(CURRENT_POWER, getCurrentPower(deviceId, portNum))
157 .cell(SERVICE_STATE, getPortServiceState(deviceId, portNum))
158 .cell(TARGET_POWER, getTargetPower(deviceId, portNum))
159 .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, portNum));
160 }
161
162 private String getPortServiceState(DeviceId deviceId, PortNumber portNumber) {
MaoLu2846b112017-05-15 17:18:55 -0700163 if (deviceService.getDevice(deviceId).type() != Type.FIBER_SWITCH) {
164 return RoadmUtil.NA;
165 }
166 Map<ConnectPoint, ProtectedTransportEndpointState> map =
167 roadmService.getProtectionSwitchStates(deviceId);
168 for (ProtectedTransportEndpointState state : map.values()) {
169 for (TransportEndpointState element : state.pathStates()) {
170 if (element.description().output().connectPoint().port().equals(portNumber)) {
171 return RoadmUtil.defaultString(element.attributes()
172 .get(OpticalAnnotations.INPUT_PORT_STATUS), RoadmUtil.UNKNOWN);
173 }
174 }
175 }
176 return RoadmUtil.UNKNOWN;
MaoLu937cf422017-03-03 23:31:46 -0800177 }
178
179 private Frequency minFreq = null, maxFreq = null, channelSpacing = null;
180 // Gets min frequency, max frequency, channel spacing
181 private void getFrequencyLimit(DeviceId deviceId, PortNumber portNumber) {
182 Set<OchSignal> signals = roadmService.queryLambdas(deviceId, portNumber);
183 if (signals.isEmpty()) {
184 return;
185 }
186 Comparator<OchSignal> compare =
187 (OchSignal a, OchSignal b) -> a.spacingMultiplier() - b.spacingMultiplier();
188 OchSignal minOch = Collections.min(signals, compare);
189 OchSignal maxOch = Collections.max(signals, compare);
190 minFreq = minOch.centralFrequency();
191 maxFreq = maxOch.centralFrequency();
192 channelSpacing = minOch.channelSpacing().frequency();
Jimmy Yanda878fc2016-09-02 16:32:01 -0700193 }
194
MaoLu2f7eadb2017-05-02 15:38:43 -0700195 // Returns the power range as a string, N/A if the power range not exists.
196 // The power range would be input power range or target power range determined by port property.
197 // If the port is RX direction then acquire the input power range from driver.
198 // Otherwise there will be a TX direction port, thus acquire the target power range.
199 private String getPowerRange(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800200 Range<Long> range = roadmService.inputPortPowerRange(deviceId, portNumber);
MaoLu2f7eadb2017-05-02 15:38:43 -0700201 if (range == null) {
202 range = roadmService.targetPortPowerRange(deviceId, portNumber);
203 }
MaoLu937cf422017-03-03 23:31:46 -0800204 return RoadmUtil.objectToString(range, RoadmUtil.NA);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700205 }
206
207 // Returns the current power as a string, Unknown if no value can be found.
208 private String getCurrentPower(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800209 Long currentPower = roadmService.getCurrentPortPower(deviceId, portNumber);
210 return RoadmUtil.objectToString(currentPower, RoadmUtil.UNKNOWN);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700211 }
212
213 // Returns target power as a string, Unknown if target power is expected but
214 // cannot be found, N/A if port does not have configurable target power
215 private String getTargetPower(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800216 if (!roadmService.hasPortTargetPower(deviceId, portNumber)) {
217 return RoadmUtil.NA;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700218 }
MaoLu937cf422017-03-03 23:31:46 -0800219 Long targetPower = roadmService.getTargetPortPower(deviceId, portNumber);
220 return RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700221 }
222 }
223
224
225 // Handler for setting port target power
226 private final class SetTargetPowerRequestHandler extends RequestHandler {
227
Jimmy Yanda878fc2016-09-02 16:32:01 -0700228 private static final String TARGET_POWER_ERR_MSG = "Target power range is %s.";
229
230 private SetTargetPowerRequestHandler() {
231 super(ROADM_SET_TARGET_POWER_REQ);
232 }
233
234 @Override
235 public void process(ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800236 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
Jimmy Yanda878fc2016-09-02 16:32:01 -0700237 PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong());
MaoLu937cf422017-03-03 23:31:46 -0800238 Range<Long> range = roadmService.targetPortPowerRange(deviceId, portNumber);
239 if (range == null) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700240 log.warn("Unable to determine target power range for device {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800241 return;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700242 }
MaoLu937cf422017-03-03 23:31:46 -0800243 Long targetPower = payload.get(TARGET_POWER).asLong();
244 boolean validTargetPower = range.contains(targetPower);
245 if (validTargetPower) {
246 roadmService.setTargetPortPower(deviceId, portNumber, targetPower);
247 }
248 ObjectNode rootNode = objectNode();
249 rootNode.put(ID, payload.get(ID).asText());
250 rootNode.put(RoadmUtil.VALID, validTargetPower);
251 rootNode.put(RoadmUtil.MESSAGE, String.format(TARGET_POWER_ERR_MSG, range.toString()));
252 sendMessage(ROADM_SET_TARGET_POWER_RESP, rootNode);
253 }
254 }
255
Boyuan Yanf3f6a8d2019-05-26 18:35:54 -0700256 // Handler for sync-up port target power
257 private final class SyncTargetPowerRequestHandler extends RequestHandler {
258
259 private static final String SYNCED_TARGET_POWER = "Synced target power is %s.";
260 private SyncTargetPowerRequestHandler() {
261 super(ROADM_SYNC_TARGET_POWER_REQ);
262 }
263
264 @Override
265 public void process(ObjectNode payload) {
266 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
267 PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong());
268 Long targetPower = roadmService.syncTargetPortPower(deviceId, portNumber);
269 String power = RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN);
270 ObjectNode rootNode = objectNode();
271 rootNode.put(ID, payload.get(ID).asText())
272 .put(RoadmUtil.VALID, true)
273 .put(RoadmUtil.MESSAGE, String.format(SYNCED_TARGET_POWER, power));
274 sendMessage(ROADM_SYNC_TARGET_POWER_RESP, rootNode);
275 }
276 }
277
MaoLu2846b112017-05-15 17:18:55 -0700278 // Protection switch operation type and path index
279 private static final String OPS_ARRAY_INDEX = "index";
280 private static final String OPS_ARRAY_OPERATION = "operation";
281 private static final String[] OPS_NON_AUTO_OPTS = {OPS_OPT_FORCE, OPS_OPT_MANUAL};
282
MaoLu937cf422017-03-03 23:31:46 -0800283 private final class CreateShowItemsRequestHandler extends RequestHandler {
284 private static final String SHOW_TARGET_POWER = "showTargetPower";
285 private static final String SHOW_SERVICE_STATE = "showServiceState";
286 private static final String SHOW_FLOW_ICON = "showFlowIcon";
MaoLu2846b112017-05-15 17:18:55 -0700287 private static final String OPS_PATHS = "opsOperations";
288 private static final String OPS_ARRAY_NAME = "name";
289 private static final String OPS_GROUP_FMT = "GROUP%d ";
MaoLu937cf422017-03-03 23:31:46 -0800290
291 private CreateShowItemsRequestHandler() {
292 super(ROADM_SHOW_ITEMS_REQ);
293 }
294
295 @Override
296 public void process(ObjectNode payload) {
297 DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
298 Type devType = deviceService.getDevice(did).type();
299 // Build response
300 ObjectNode node = objectNode();
MaoLu937cf422017-03-03 23:31:46 -0800301 node.put(SHOW_FLOW_ICON, devType == Type.ROADM);
MaoLu2846b112017-05-15 17:18:55 -0700302 if (devType == Type.FIBER_SWITCH) {
303 node.put(SHOW_TARGET_POWER, false);
304 node.put(SHOW_SERVICE_STATE, true);
305 // add protection switch paths
306 putProtectionSwitchPaths(did, node);
307 } else {
308 node.put(SHOW_TARGET_POWER, true);
309 node.put(SHOW_SERVICE_STATE, false);
310 }
MaoLu937cf422017-03-03 23:31:46 -0800311 sendMessage(ROADM_SHOW_ITEMS_RESP, node);
312 }
MaoLu2846b112017-05-15 17:18:55 -0700313
314 private void putProtectionSwitchPaths(DeviceId deviceId, ObjectNode node) {
315 Map<ConnectPoint, ProtectedTransportEndpointState> states =
316 roadmService.getProtectionSwitchStates(deviceId);
317 ArrayNode nodes = node.putArray(OPS_PATHS);
318 // Add path names for every identifier.
319 int groupIndex = 0;
320 for (ConnectPoint identifier : states.keySet()) {
321 // No group name needed if there is only one connection point identifier.
322 String groupName = states.keySet().size() == 1 ? "" : String.format(OPS_GROUP_FMT, ++groupIndex);
323 // Add AUTOMATIC operation.
324 nodes.add(new ObjectNode(JsonNodeFactory.instance)
325 .put(OPS_ARRAY_INDEX, ACTIVE_UNKNOWN)
326 .put(OPS_ARRAY_OPERATION, OPS_OPT_AUTO)
327 .put(OPS_ARRAY_NAME, String.format("%s%s", groupName, OPS_OPT_AUTO)));
328 // Add FORCE and MANUAL operations for every path.
329 for (String opt : OPS_NON_AUTO_OPTS) {
330 int pathIndex = 0;
331 for (TransportEndpointState state : states.get(identifier).pathStates()) {
332 nodes.add(new ObjectNode(JsonNodeFactory.instance)
333 .put(OPS_ARRAY_INDEX, pathIndex++)
334 .put(OPS_ARRAY_OPERATION, opt)
335 .put(OPS_ARRAY_NAME,
336 String.format("%s%s %s", groupName, opt, state.id().id().toUpperCase())));
337 }
338 }
339 }
340
341
342 }
MaoLu937cf422017-03-03 23:31:46 -0800343 }
344
345 private final class CreateOpsModeSetRequestHandler extends RequestHandler {
MaoLu937cf422017-03-03 23:31:46 -0800346 private static final String DEVICE_INVALID_ERR_MSG = "Apply failed: device is offline or unavailable.";
347 private static final String TYPE_INVALID_ERR_MSG = "Apply failed: invalid device type.";
348
349 private CreateOpsModeSetRequestHandler() {
350 super(ROADM_SET_OPS_MODE_REQ);
351 }
352
353 @Override
354 public void process(ObjectNode payload) {
355 DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
356 ObjectNode node = objectNode();
357 if (!deviceService.isAvailable(did)) {
358 node.put(RoadmUtil.VALID, false);
359 node.put(RoadmUtil.MESSAGE, DEVICE_INVALID_ERR_MSG);
360 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
361 return;
362 }
363 Type devType = deviceService.getDevice(did).type();
364 if (devType != Type.FIBER_SWITCH) {
365 node.put(RoadmUtil.VALID, false);
366 node.put(RoadmUtil.MESSAGE, TYPE_INVALID_ERR_MSG);
367 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
368 return;
369 }
MaoLu2846b112017-05-15 17:18:55 -0700370 // get switch configuration from payload, and then switch the device.
371 roadmService.configProtectionSwitch(did, string(payload, OPS_ARRAY_OPERATION),
372 roadmService.getProtectionSwitchStates(did).keySet().toArray(new ConnectPoint[0])[0],
373 (int) number(payload, OPS_ARRAY_INDEX));
MaoLu937cf422017-03-03 23:31:46 -0800374 node.put(RoadmUtil.VALID, true);
375 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700376 }
377 }
378}