blob: cf9ad217018b9548cde6dc58d3c904ea4025e8a5 [file] [log] [blame]
Marc De Leenheer57a5af02016-12-02 20:54:41 -08001/*
2 * Copyright 2016-present Open Networking Laboratory
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 */
16package org.onosproject.drivers.lumentum;
17
18import org.onlab.packet.ChassisId;
19import org.onosproject.net.ChannelSpacing;
20import org.onosproject.net.CltSignalType;
21import org.onosproject.net.DefaultAnnotations;
22import org.onosproject.net.Device;
23import org.onosproject.net.DeviceId;
24import org.onosproject.net.GridType;
25import org.onosproject.net.OchSignal;
26import org.onosproject.net.OduSignalType;
27import org.onosproject.net.PortNumber;
28import org.onosproject.net.SparseAnnotations;
29import org.onosproject.net.device.DefaultDeviceDescription;
30import org.onosproject.net.device.DeviceDescription;
31import org.onosproject.net.device.DeviceDescriptionDiscovery;
32import org.onosproject.net.device.PortDescription;
33import org.onosproject.net.driver.AbstractHandlerBehaviour;
34import org.onosproject.tl1.Tl1Command;
35import org.onosproject.tl1.Tl1Controller;
36import org.onosproject.tl1.Tl1Device;
37import org.onosproject.tl1.impl.DefaultTl1Command;
38import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.Collections;
44import java.util.List;
45import java.util.Optional;
46import java.util.concurrent.ExecutionException;
47import java.util.concurrent.Future;
48import java.util.concurrent.TimeUnit;
49import java.util.concurrent.TimeoutException;
50
51import static com.google.common.base.Preconditions.checkNotNull;
52import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
53import static org.onosproject.net.optical.device.OduCltPortHelper.oduCltPortDescription;
54
55/**
56 * Device description behaviour for Lumentum WaveReady devices.
57 *
58 * Tested with Lumentum WaveReady 3100 transponder.
59 */
60public class LumentumWaveReadyDiscovery extends AbstractHandlerBehaviour implements DeviceDescriptionDiscovery {
61 private final Logger log = LoggerFactory.getLogger(LumentumWaveReadyDiscovery.class);
62
63 // Time to wait for device response in milliseconds
64 private static final int TIMEOUT = 10000;
65
66 private static final String LUMENTUM = "Lumentum";
67 private static final String WAVEREADY = "WaveReady";
68 private static final String SWVERSION = "1.0";
69 private static final String SERIAL = "3100";
70
71 // Some TL1 string constants
72 private static final String ACT = "ACT";
73 private static final String USER = "USER";
74 private static final String RTRV = "RTRV";
75 private static final String NETYPE = "NETYPE";
76 private static final String PLUGGABLE_INV = "PLUGGABLE-INV";
77 private static final String CANC = "CANC";
78 private static final String EIGHTFIFTY = "850";
79
80
81 @Override
82 public DeviceDescription discoverDeviceDetails() {
83 DeviceId deviceId = handler().data().deviceId();
84 Tl1Controller ctrl = checkNotNull(handler().get(Tl1Controller.class));
85 // Something reasonable, unavailable by default
86 DeviceDescription defaultDescription = new DefaultDeviceDescription(deviceId.uri(), Device.Type.OTN,
87 LUMENTUM, WAVEREADY, SWVERSION, SERIAL,
88 new ChassisId(), false, DefaultAnnotations.EMPTY);
89
90 Optional<Tl1Device> device = ctrl.getDevice(deviceId);
91 if (!device.isPresent()) {
92 return defaultDescription;
93 }
94
95 // Login
96 Tl1Command loginCmd = DefaultTl1Command.builder()
97 .withVerb(ACT)
98 .withModifier(USER)
99 .withAid(device.get().username())
100 .withCtag(100)
101 .withParameters(device.get().password())
102 .build();
103 Future<String> login = ctrl.sendMsg(deviceId, loginCmd);
104
105 try {
106 String loginResponse = login.get(TIMEOUT, TimeUnit.MILLISECONDS);
107 if (loginResponse.contains("Access denied")) {
108 log.error("Access denied: {}", loginResponse);
109 return defaultDescription;
110 }
111 } catch (InterruptedException | ExecutionException | TimeoutException e) {
112 log.error("Login failed", e);
113 return defaultDescription;
114 }
115
116 // Fetch device description
117 Tl1Command ddCmd = DefaultTl1Command.builder()
118 .withVerb(RTRV)
119 .withModifier(NETYPE)
120 .withCtag(101)
121 .build();
122 Future<String> dd = ctrl.sendMsg(deviceId, ddCmd);
123
124 try {
125 String ddResponse = dd.get(TIMEOUT, TimeUnit.MILLISECONDS);
126
127 return new DefaultDeviceDescription(defaultDescription, true, extractAnnotations(ddResponse));
128 } catch (InterruptedException | ExecutionException | TimeoutException e) {
129 log.error("Device description not found", e);
130 return defaultDescription;
131 }
132 }
133
134 @Override
135 public List<PortDescription> discoverPortDetails() {
136 DeviceId deviceId = handler().data().deviceId();
137 Tl1Controller ctrl = checkNotNull(handler().get(Tl1Controller.class));
138
139 // Assume we're successfully logged in
140 // Fetch port descriptions
141 Tl1Command pdCmd = DefaultTl1Command.builder()
142 .withVerb(RTRV)
143 .withModifier(PLUGGABLE_INV)
144 .withCtag(102)
145 .build();
146 Future<String> pd = ctrl.sendMsg(deviceId, pdCmd);
147
148 try {
149 String pdResponse = pd.get(TIMEOUT, TimeUnit.MILLISECONDS);
150
151 return extractPorts(pdResponse);
152 } catch (InterruptedException | ExecutionException | TimeoutException e) {
153 log.error("Port description not found", e);
154 return Collections.EMPTY_LIST;
155 }
156 }
157
158 private SparseAnnotations extractAnnotations(String s) {
159 DefaultAnnotations.Builder annot = DefaultAnnotations.builder();
160
161 Arrays.stream(s.split(",")).forEach(w -> {
162 String[] pair = w.replaceAll("\\\\\"", "").split("=");
163 if (pair.length == 2) {
164 annot.set(pair[0], pair[1]);
165 } else {
166 annot.set(pair[0], "");
167 }
168 });
169
170 return annot.build();
171 }
172
173 // Extract ports from response on pluggable inventory retrieval.
174 // Client ports are identified by 850nm, everything else is a network port.
175 private List<PortDescription> extractPorts(String s) {
176 List<PortDescription> ports = new ArrayList<>();
177
178 if (s.length() == 0) {
179 return ports;
180 }
181
182 Arrays.stream(s.split("\"\"")).forEach(p -> {
183 if (p.contains(EIGHTFIFTY)) {
184 PortDescription cltPort = oduCltPortDescription(
185 PortNumber.portNumber(ports.size() + 1),
186 true,
187 CltSignalType.CLT_10GBE,
188 extractAnnotations(p));
189 ports.add(cltPort);
190 } else {
191 PortDescription netPort = ochPortDescription(
192 PortNumber.portNumber(ports.size() + 1),
193 true,
194 OduSignalType.ODU2e,
195 true,
196 new OchSignal(GridType.DWDM, ChannelSpacing.CHL_50GHZ, 0, 4),
197 extractAnnotations(p));
198 ports.add(netPort);
199 }
200 });
201
202 return ports;
203 }
204
205 // Unused but provided here for convenience.
206 private void logout() {
207 DeviceId deviceId = handler().data().deviceId();
208 Tl1Controller ctrl = checkNotNull(handler().get(Tl1Controller.class));
209
210 Optional<Tl1Device> device = ctrl.getDevice(deviceId);
211 if (!device.isPresent()) {
212 return;
213 }
214
215 // Logout command
216 Tl1Command logoutCmd = DefaultTl1Command.builder()
217 .withVerb(CANC)
218 .withModifier(USER)
219 .withAid(device.get().username())
220 .withCtag(103)
221 .build();
222 Future<String> logout = ctrl.sendMsg(deviceId, logoutCmd);
223
224 try {
225 String logoutResponse = logout.get(TIMEOUT, TimeUnit.MILLISECONDS);
226
227 } catch (InterruptedException | ExecutionException | TimeoutException e) {
228 log.error("Lougout failed", e);
229 }
230 }
231}