blob: a27113268374f13412e5b9e12be1c270d00a0d92 [file] [log] [blame]
Rohit Singh16d4df92019-07-15 19:33:05 +05301/*
2 * Copyright 2019-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 * This Work is contributed by Sterlite Technologies
17 */
18
19package org.onosproject.drivers.odtn;
20
21import com.fasterxml.jackson.databind.JsonNode;
22import com.fasterxml.jackson.databind.ObjectMapper;
23import org.apache.commons.configuration.HierarchicalConfiguration;
24import org.apache.commons.configuration.XMLConfiguration;
25import org.onlab.osgi.DefaultServiceDirectory;
26import org.onosproject.drivers.odtn.util.NetconfSessionUtility;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.Direction;
29import org.onosproject.net.ModulationScheme;
30import org.onosproject.net.OchSignal;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.behaviour.ModulationConfig;
33import org.onosproject.net.device.DeviceService;
34import org.onosproject.net.driver.AbstractHandlerBehaviour;
35import org.onosproject.netconf.NetconfController;
36import org.onosproject.netconf.NetconfSession;
37import org.slf4j.Logger;
38import org.slf4j.LoggerFactory;
39
40import java.io.IOException;
41import java.util.Optional;
42
43import static com.google.common.base.Preconditions.checkNotNull;
44
45/*
46 * Driver Implementation of the ModulationConfig for OpenConfig terminal devices.
47 */
48public class CassiniModulationConfig<T> extends AbstractHandlerBehaviour implements ModulationConfig<T> {
49
50
51 private static final String RPC_TAG_NETCONF_BASE =
52 "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
53
54 private static final String RPC_CLOSE_TAG = "</rpc>";
55
56 private static final Logger log = LoggerFactory.getLogger(CassiniModulationConfig.class);
57
58 private ComponentType state = ComponentType.DIRECTION;
59
60 private static final double OSNR_THRESHOLD_VALUE = 13.0;
61
62
63 enum BitRate {
64 GBPS_200(200), // 200 Gbps
65 GBPS_100(100), // 100 Gbps
66 GBPS_40(40), // 40 Gbps
67 GBPS_10(10); // 10 Gbps
68
69 private final long value;
70
71 public long getValue() {
72 return value;
73 }
74
75 BitRate(long value) {
76 this.value = value;
77 }
78 }
79
80 private NetconfController getController() {
81 return handler().get(NetconfController.class);
82 }
83
84 /*
85 *
86 * Get the deviceId for which the methods apply.
87 *
88 * @return The deviceId as contained in the handler data
89 */
90
91
92 private DeviceId getDeviceId() {
93 return handler().data().deviceId();
94 }
95
96
97 /**
98 * Get the target Modulation Scheme on the component.
99 *
100 * @param port the port
101 * @param component the port component
102 * @return ModulationScheme as per bitRate value
103 **/
104 @Override
105 public Optional<ModulationScheme> getModulationScheme(PortNumber port, T component) {
106 checkType(component);
107 return state.getModulationScheme(port, component);
108 }
109
110 /**
111 * Set the target Modulation Scheme on the component.
112 *
113 * @param port the port
114 * @param component the port component
115 * @param bitRate bit rate in bps
116 **/
117 @Override
118 public void setModulationScheme(PortNumber port, T component, long bitRate) {
119 checkType(component);
120 state.setModulationScheme(port, component, bitRate);
121 }
122
123 /*
124 *
125 * Set the ComponentType to invoke proper methods for different template T.
126 * @param component the component.
127 */
128 void checkType(Object component) {
129 String clsName = component.getClass().getName();
130
131 if (component instanceof Direction) {
132 state = CassiniModulationConfig.ComponentType.DIRECTION;
133 } else if (component instanceof OchSignal) {
134 state = CassiniModulationConfig.ComponentType.OCHSIGNAL;
135 } else {
136 log.error("Cannot parse the component type {}.", clsName);
137 }
138
139
140 state.cassini = this;
141 }
142
143 /*
144 *
145 * Component type.
146 */
147
148
149 enum ComponentType {
150
151 /*
152 *
153 * Direction.
154 */
155
156
157 DIRECTION() {
158 @Override
159 Optional<ModulationScheme> getModulationScheme(PortNumber port, Object component) {
160 return super.getModulationScheme(port, component);
161 }
162
163 @Override
164 void setModulationScheme(PortNumber port, Object component, long bitRate) {
165 super.setModulationScheme(port, component, bitRate);
166 }
167 },
168
169 /**
170 * OchSignal.
171 */
172
173
174 OCHSIGNAL() {
175 @Override
176 Optional<ModulationScheme> getModulationScheme(PortNumber port, Object component) {
177 return super.getModulationScheme(port, component);
178 }
179
180 @Override
181 void setModulationScheme(PortNumber port, Object component, long bitRate) {
182 super.setModulationScheme(port, component, bitRate);
183 }
184 };
185
186
187 CassiniModulationConfig cassini;
188
189 /*
190 * mirror method in the internal class.
191 * @param port port
192 * @param component component
193 * @return target modulation
194 */
195 Optional<ModulationScheme> getModulationScheme(PortNumber port, Object component) {
196 NetconfSession session = NetconfSessionUtility
197 .getNetconfSession(cassini.getDeviceId(), cassini.getController());
198 checkNotNull(session);
199 String filter = createModulationFilter(cassini, port);
200 StringBuilder rpcReq = new StringBuilder();
201 rpcReq.append(RPC_TAG_NETCONF_BASE)
202 .append("<get>")
203 .append("<filter>")
204 .append(filter)
205 .append("</filter>")
206 .append("</get>")
207 .append(RPC_CLOSE_TAG);
208 log.info("RPC Call for Getting Modulation : \n {}", rpcReq.toString());
209 XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
210 try {
211 HierarchicalConfiguration config =
Andrea Campanella3a361452019-08-02 10:17:53 +0200212 xconf.configurationAt("components/component/optical-channel/config");
Rohit Singh16d4df92019-07-15 19:33:05 +0530213
214 String modulationScheme = String.valueOf(config.getString("modulation"));
215
216 return Optional.of(ModulationScheme.valueOf(modulationScheme));
217 } catch (IllegalArgumentException e) {
218 return Optional.empty();
219 }
220 }
221
222 /*
223 * mirror method in the internal class.
224 * @param port port
225 * @param component component
226 * @param power target value
227 */
228 void setModulationScheme(PortNumber port, Object component, long bitRate) {
229
230 ModulationScheme modulation = null;
231 String editConfig = null;
232 double osnr = 0.0;
233 boolean rpcResponse = false;
234 boolean receiver = false;
235
236 // TODO OSNR is valid only for receiver so need to modify
237 /*if(component.toString().equals(Direction.INGRESS.toString())){
238 receiver=true;
239 }*/
240
241 //check if bitrate is less than equal to 100 Gig
242 if (bitRate <= BitRate.GBPS_100.value) {
243 modulation = ModulationScheme.DP_QPSK;
244 editConfig = modulationEditConfig(cassini, port, component, bitRate, modulation.name());
245 //setting the modulation by calling rpc
246 rpcResponse = setModulationRpc(port, component, editConfig);
247 if (rpcResponse) {
248 // TODO OSNR is valid only for receiver so need to modify
249 osnr = fetchDeviceSnr(cassini, port);
250 if (osnr <= OSNR_THRESHOLD_VALUE) {
251 log.error("Channel not possible for this OSNR Value : {}", osnr);
252 }
253 }
254 } else { // check if bitrate is greater than 100 Gig
255 modulation = ModulationScheme.DP_16QAM;
256 editConfig = modulationEditConfig(cassini, port, component, bitRate, modulation.name());
257 //setting the modulation by calling rpc
258 rpcResponse = setModulationRpc(port, component, editConfig);
259 if (rpcResponse) {
260 //TODO OSNR is valid only for receiver so need to modify
261 osnr = fetchDeviceSnr(cassini, port);
262 if (osnr <= OSNR_THRESHOLD_VALUE) {
263 modulation = ModulationScheme.DP_8QAM;
264 editConfig = modulationEditConfig(cassini, port, component, bitRate, modulation.name());
265 //setting the modulation by calling rpc
266 rpcResponse = setModulationRpc(port, component, editConfig);
267 if (rpcResponse) {
268 // TODO OSNR is valid only for receiver so need to modify
269 osnr = fetchDeviceSnr(cassini, port);
270 if (osnr <= OSNR_THRESHOLD_VALUE) {
271 log.warn("Channel not possible for this OSNR Value : {}." +
272 " Please reduce the channel bitrate.", osnr);
273 }
274 }
275 }
276 }
277 }
278
279
280 }
281
282
283 /*
284 * Get filtered content under <optical-channel><state>.
285 * @param pc power config instance
286 * @param port the port number
287 * @param underState the filter condition
288 * @return RPC reply
289 */
290
291 //RPC call for OSNR still not finalised, need to update Rpc once validated
292 private static XMLConfiguration getTerminalDeviceSnr(CassiniModulationConfig config, PortNumber port) {
293 NetconfSession session = NetconfSessionUtility
294 .getNetconfSession(config.getDeviceId(), config.getController());
295 checkNotNull(session);
296 String name = ocName(config, port);
297 StringBuilder rpcReq = new StringBuilder(RPC_TAG_NETCONF_BASE);
298 rpcReq.append("<get><filter>")
299 .append("<osnr xmlns=\"http://openconfig.net/yang/terminal-device\">")
300 .append("<instant/>")
301 .append("</osnr></filter></get>")
302 .append(RPC_CLOSE_TAG);
303 log.info("RPC Call for Fetching OSNR :\n\n {}", rpcReq.toString());
304 XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
305 return xconf;
306 }
307
308 private static String createModulationFilter(CassiniModulationConfig modulationConfig, PortNumber portNumber) {
309 String name = ocName(modulationConfig, portNumber);
310 StringBuilder sb = new StringBuilder("<components xmlns=\"http://openconfig.net/yang/platform\">");
311 sb.append("<component>").append("<name>").append(name).append("</name>");
312 sb.append("<optical-channel xmlns=\"http://openconfig.net/yang/terminal-device\">");
313 sb.append("<config><modulation/></config>");
314 sb.append("</optical-channel>");
315 sb.append("</component>").append("</components>");
316 return sb.toString();
317 }
318
319 /**
320 * Extract component name from portNumber's annotations.
321 *
322 * @param pc modulation config instance
323 * @param portNumber the port number
324 * @return the component name
325 */
326
327
328 private static String ocName(CassiniModulationConfig pc, PortNumber portNumber) {
329 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
330 DeviceId deviceId = pc.handler().data().deviceId();
331 return deviceService.getPort(deviceId, portNumber).annotations().value("oc-name");
332 }
333
334 private static String channelSpacing(CassiniModulationConfig modulationConfig, PortNumber portNumber) {
335 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
336 DeviceId deviceId = modulationConfig.handler().data().deviceId();
337 String lambda = deviceService.getPort(deviceId, portNumber).annotations().value("lambda");
338
339 ObjectMapper mapper = new ObjectMapper();
340 String channelSpacing = "";
341 try {
342 JsonNode actualObj = mapper.readTree(lambda);
343 JsonNode csNode = actualObj.get("channelSpacing");
344 channelSpacing = csNode.asText();
345 log.info("Channel_Spacing : " + channelSpacing);
346
347 } catch (IOException e) {
348 log.error("Error while parsing Json");
349 }
350 return channelSpacing;
351
352 }
353
354 private double fetchDeviceSnr(CassiniModulationConfig modulationConfig, PortNumber portNumber) {
355 double osnr = 0.0;
356 XMLConfiguration xconf = getTerminalDeviceSnr(cassini, portNumber);
357 if (xconf == null) {
358 return osnr;
359 }
360 try {
361 HierarchicalConfiguration config =
362 xconf.configurationAt("data/components/component/optical-channel/state/osnr");
363 osnr = Float.valueOf(config.getString("snr")).doubleValue();
364 return osnr;
365 } catch (IllegalArgumentException e) {
366 return osnr;
367 }
368 }
369 /*
370 *
371 * Parse filtering string from port and component.
372 * @param portNumber Port Number
373 * @param component port component (optical-channel)
374 * @param bitRate bitRate in bps
375 * @return filtering string in xml format
376
377 */
378
379 private String modulationEditConfig(CassiniModulationConfig modulationConfig, PortNumber portNumber,
380 Object component, long bitRate, String modulation) {
381 if (component != null) {
382 String portName = ocName(modulationConfig, portNumber);
383 //String channelSpacing = channelSpacing(modulationConfig,portNumber);
384 //ChannelSpacing cs= ChannelSpacing.valueOf(channelSpacing);
385 //double csValue= cs.frequency().asGHz();
386
387 StringBuilder sb = new StringBuilder("<components xmlns=\"http://openconfig.net/yang/platform\">");
388 sb.append("<component>").append("<name>").append(portName).append("</name>");
389 if (modulation != null) {
390 // This is an edit-config operation.
391 sb.append("<optical-channel xmlns=\"http://openconfig.net/yang/terminal-device\">")
392 .append("<config>")
393 .append("<modulation>")
394 .append(modulation)
395 .append("</modulation>")
396 .append("</config>")
397 .append("</optical-channel>");
398 }
399 sb.append("</component>").append("</components>");
400 return sb.toString();
401 } else {
402 log.error("Cannot process the component {}.", component.getClass());
403 return null;
404 }
405 }
406
407 private boolean setModulationRpc(PortNumber port, Object component, String editConfig) {
408 NetconfSession session = NetconfSessionUtility
409 .getNetconfSession(cassini.getDeviceId(), cassini.getController());
410 checkNotNull(session);
411 boolean response = true;
412 StringBuilder rpcReq = new StringBuilder();
413 rpcReq.append(RPC_TAG_NETCONF_BASE)
414 .append("<edit-config>")
415 .append("<target><running/></target>")
416 .append("<config>")
417 .append(editConfig)
418 .append("</config>")
419 .append("</edit-config>")
420 .append(RPC_CLOSE_TAG);
421 log.info("RPC call for Setting Modulation : {}", rpcReq.toString());
422 XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
423
424 // The successful reply should be "<rpc-reply ...><ok /></rpc-reply>"
425 if (!xconf.getRoot().getChild(0).getName().equals("ok")) {
426 response = false;
427 log.error("The <edit-config> operation to set target-modulation of Port({}:{}) is failed.",
428 port.toString(), component.toString());
429 }
430 return response;
431 }
432 }
433
434
435}