blob: cf9ad217018b9548cde6dc58d3c904ea4025e8a5 [file] [log] [blame]
/*
* 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.drivers.lumentum;
import org.onlab.packet.ChassisId;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.CltSignalType;
import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.GridType;
import org.onosproject.net.OchSignal;
import org.onosproject.net.OduSignalType;
import org.onosproject.net.PortNumber;
import org.onosproject.net.SparseAnnotations;
import org.onosproject.net.device.DefaultDeviceDescription;
import org.onosproject.net.device.DeviceDescription;
import org.onosproject.net.device.DeviceDescriptionDiscovery;
import org.onosproject.net.device.PortDescription;
import org.onosproject.net.driver.AbstractHandlerBehaviour;
import org.onosproject.tl1.Tl1Command;
import org.onosproject.tl1.Tl1Controller;
import org.onosproject.tl1.Tl1Device;
import org.onosproject.tl1.impl.DefaultTl1Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
import static org.onosproject.net.optical.device.OduCltPortHelper.oduCltPortDescription;
/**
* Device description behaviour for Lumentum WaveReady devices.
*
* Tested with Lumentum WaveReady 3100 transponder.
*/
public class LumentumWaveReadyDiscovery extends AbstractHandlerBehaviour implements DeviceDescriptionDiscovery {
private final Logger log = LoggerFactory.getLogger(LumentumWaveReadyDiscovery.class);
// Time to wait for device response in milliseconds
private static final int TIMEOUT = 10000;
private static final String LUMENTUM = "Lumentum";
private static final String WAVEREADY = "WaveReady";
private static final String SWVERSION = "1.0";
private static final String SERIAL = "3100";
// Some TL1 string constants
private static final String ACT = "ACT";
private static final String USER = "USER";
private static final String RTRV = "RTRV";
private static final String NETYPE = "NETYPE";
private static final String PLUGGABLE_INV = "PLUGGABLE-INV";
private static final String CANC = "CANC";
private static final String EIGHTFIFTY = "850";
@Override
public DeviceDescription discoverDeviceDetails() {
DeviceId deviceId = handler().data().deviceId();
Tl1Controller ctrl = checkNotNull(handler().get(Tl1Controller.class));
// Something reasonable, unavailable by default
DeviceDescription defaultDescription = new DefaultDeviceDescription(deviceId.uri(), Device.Type.OTN,
LUMENTUM, WAVEREADY, SWVERSION, SERIAL,
new ChassisId(), false, DefaultAnnotations.EMPTY);
Optional<Tl1Device> device = ctrl.getDevice(deviceId);
if (!device.isPresent()) {
return defaultDescription;
}
// Login
Tl1Command loginCmd = DefaultTl1Command.builder()
.withVerb(ACT)
.withModifier(USER)
.withAid(device.get().username())
.withCtag(100)
.withParameters(device.get().password())
.build();
Future<String> login = ctrl.sendMsg(deviceId, loginCmd);
try {
String loginResponse = login.get(TIMEOUT, TimeUnit.MILLISECONDS);
if (loginResponse.contains("Access denied")) {
log.error("Access denied: {}", loginResponse);
return defaultDescription;
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error("Login failed", e);
return defaultDescription;
}
// Fetch device description
Tl1Command ddCmd = DefaultTl1Command.builder()
.withVerb(RTRV)
.withModifier(NETYPE)
.withCtag(101)
.build();
Future<String> dd = ctrl.sendMsg(deviceId, ddCmd);
try {
String ddResponse = dd.get(TIMEOUT, TimeUnit.MILLISECONDS);
return new DefaultDeviceDescription(defaultDescription, true, extractAnnotations(ddResponse));
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error("Device description not found", e);
return defaultDescription;
}
}
@Override
public List<PortDescription> discoverPortDetails() {
DeviceId deviceId = handler().data().deviceId();
Tl1Controller ctrl = checkNotNull(handler().get(Tl1Controller.class));
// Assume we're successfully logged in
// Fetch port descriptions
Tl1Command pdCmd = DefaultTl1Command.builder()
.withVerb(RTRV)
.withModifier(PLUGGABLE_INV)
.withCtag(102)
.build();
Future<String> pd = ctrl.sendMsg(deviceId, pdCmd);
try {
String pdResponse = pd.get(TIMEOUT, TimeUnit.MILLISECONDS);
return extractPorts(pdResponse);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error("Port description not found", e);
return Collections.EMPTY_LIST;
}
}
private SparseAnnotations extractAnnotations(String s) {
DefaultAnnotations.Builder annot = DefaultAnnotations.builder();
Arrays.stream(s.split(",")).forEach(w -> {
String[] pair = w.replaceAll("\\\\\"", "").split("=");
if (pair.length == 2) {
annot.set(pair[0], pair[1]);
} else {
annot.set(pair[0], "");
}
});
return annot.build();
}
// Extract ports from response on pluggable inventory retrieval.
// Client ports are identified by 850nm, everything else is a network port.
private List<PortDescription> extractPorts(String s) {
List<PortDescription> ports = new ArrayList<>();
if (s.length() == 0) {
return ports;
}
Arrays.stream(s.split("\"\"")).forEach(p -> {
if (p.contains(EIGHTFIFTY)) {
PortDescription cltPort = oduCltPortDescription(
PortNumber.portNumber(ports.size() + 1),
true,
CltSignalType.CLT_10GBE,
extractAnnotations(p));
ports.add(cltPort);
} else {
PortDescription netPort = ochPortDescription(
PortNumber.portNumber(ports.size() + 1),
true,
OduSignalType.ODU2e,
true,
new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 0, 4),
extractAnnotations(p));
ports.add(netPort);
}
});
return ports;
}
// Unused but provided here for convenience.
private void logout() {
DeviceId deviceId = handler().data().deviceId();
Tl1Controller ctrl = checkNotNull(handler().get(Tl1Controller.class));
Optional<Tl1Device> device = ctrl.getDevice(deviceId);
if (!device.isPresent()) {
return;
}
// Logout command
Tl1Command logoutCmd = DefaultTl1Command.builder()
.withVerb(CANC)
.withModifier(USER)
.withAid(device.get().username())
.withCtag(103)
.build();
Future<String> logout = ctrl.sendMsg(deviceId, logoutCmd);
try {
String logoutResponse = logout.get(TIMEOUT, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
log.error("Lougout failed", e);
}
}
}