blob: 3a2a95ee6b2c09006d1aed42a71ff818f883be3d [file] [log] [blame]
Sudeep Desai5013f492020-01-08 16:01:47 +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.DatastoreId;
36import org.onosproject.netconf.NetconfController;
37import org.onosproject.netconf.NetconfException;
38import org.onosproject.netconf.NetconfSession;
39import org.slf4j.Logger;
40import org.slf4j.LoggerFactory;
41
42import java.io.IOException;
43import java.util.Optional;
44
45import static com.google.common.base.Preconditions.checkNotNull;
46
47/*
48 * Driver Implementation of the ModulationConfig for OpenConfig terminal devices.
49 */
50public class TerminalDeviceModulationConfig<T> extends AbstractHandlerBehaviour implements ModulationConfig<T> {
51
52
53 public static final String RPC_TAG_NETCONF_BASE =
54 "<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">";
55
56 public static final String RPC_CLOSE_TAG = "</rpc>";
57
58 public static Logger log = LoggerFactory.getLogger(TerminalDeviceModulationConfig.class);
59
60 public TerminalDeviceModulationConfig.ComponentType state = ComponentType.DIRECTION;
61
62 private static final double OSNR_THRESHOLD_VALUE = 13.0;
63
64
65 public enum BitRate {
66 GBPS_200(200), // 200 Gbps
67 GBPS_100(100), // 100 Gbps
68 GBPS_40(40), // 40 Gbps
69 GBPS_10(10); // 10 Gbps
70
71 final long value;
72
73 public long getValue() {
74 return value;
75 }
76
77 BitRate(long value) {
78 this.value = value;
79 }
80 }
81
82 public NetconfController getController() {
83 return handler().get(NetconfController.class);
84 }
85
86 /*
87 *
88 * Get the deviceId for which the methods apply.
89 *
90 * @return The deviceId as contained in the handler data
91 */
92
93
94 public DeviceId getDeviceId() {
95 return handler().data().deviceId();
96 }
97
98 /**
99 * Construct a rpc target power message.
100 *
101 * @param filter to build rpc
102 * @return RPC payload
103 */
104 public StringBuilder getModulationSchemeRequestRpc(String filter) {
105 StringBuilder rpc = new StringBuilder();
Sudeep Desaibffe1532020-01-21 16:43:46 +0530106 rpc.append("<get-config>")
107 .append("<source>")
108 .append("<" + DatastoreId.RUNNING + "/>")
109 .append("</source>")
110 .append("<filter type='subtree'>")
Sudeep Desai5013f492020-01-08 16:01:47 +0530111 .append(filter)
112 .append("</filter>")
Sudeep Desaibffe1532020-01-21 16:43:46 +0530113 .append("</get-config>");
Sudeep Desai5013f492020-01-08 16:01:47 +0530114 return rpc;
115 }
Sudeep Desai5013f492020-01-08 16:01:47 +0530116 /**
117 * Construct a rpc target power message.
118 *
119 * @return RPC payload
120 */
121 public DatastoreId getDataStoreId() {
122 return DatastoreId.RUNNING;
123 }
124
125 /**
126 * Construct a rpc target power message.
127 *
128 * @param name for optical channel name
129 * @return RPC payload
130 */
131 public StringBuilder createModulationFilterRequestRpc(String name) {
132 StringBuilder rpc = new StringBuilder();
133 rpc.append("<name>").append(name).append("</name>");
134 rpc.append("<optical-channel xmlns=\"http://openconfig.net/yang/terminal-device\">");
135 rpc.append("<config><modulation/></config>");
136 rpc.append("</optical-channel>");
137 return rpc;
138 }
139
140 /*
141 *
142 * Parse filtering string from port and component.
143 * @param portNumber Port Number
144 * @param component port component (optical-channel)
145 * @param bitRate bitRate in bps
146 * @return filtering string in xml format
147
148 */
149 public String modulationEditConfigRequestRpc(TerminalDeviceModulationConfig modulationConfig, PortNumber portNumber,
150 Object component, long bitRate, String modulation) {
151 if (component != null) {
152 String portName = state.ocName(modulationConfig, portNumber);
153 //String channelSpacing = channelSpacing(modulationConfig,portNumber);
154 //ChannelSpacing cs= ChannelSpacing.valueOf(channelSpacing);
155 //double csValue= cs.frequency().asGHz();
156
157 StringBuilder sb = new StringBuilder("<components xmlns=\"http://openconfig.net/yang/platform\">");
158 sb.append("<component>").append("<name>").append(portName).append("</name>");
159 if (modulation != null) {
160 // This is an edit-config operation.
161 sb.append("<optical-channel xmlns=\"http://openconfig.net/yang/terminal-device\">")
162 .append("<config>")
163 .append("<modulation>")
164 .append(modulation)
165 .append("</modulation>")
166 .append("</config>")
167 .append("</optical-channel>");
168 }
169 sb.append("</component>").append("</components>");
170 return sb.toString();
171 } else {
172 log.error("Cannot process the component {}.", component.getClass());
173 return null;
174 }
175 }
176
177 public void setModulationSchemeProcessor(PortNumber port, Object component, long bitRate) {
178 ModulationScheme modulation = null;
179 String editConfig = null;
180 double osnr = 0.0;
181 boolean rpcResponse = false;
182 boolean receiver = false;
183
184 // TODO OSNR is valid only for receiver so need to modify
185 /*if(component.toString().equals(Direction.INGRESS.toString())){
186 receiver=true;
187 }*/
188
189 //check if bitrate is less than equal to 100 Gig
190 if (bitRate <= BitRate.GBPS_100.value) {
191 modulation = ModulationScheme.DP_QPSK;
Sudeep Desaibffe1532020-01-21 16:43:46 +0530192 editConfig = state.modulationEditConfig(state.terminalDevice, port, component, bitRate, modulation.name());
Sudeep Desai5013f492020-01-08 16:01:47 +0530193 //setting the modulation by calling rpc
194 rpcResponse = state.setModulationRpc(port, component, editConfig);
195 if (rpcResponse) {
196 // TODO OSNR is valid only for receiver so need to modify
Sudeep Desaibffe1532020-01-21 16:43:46 +0530197 osnr = state.fetchDeviceSnr(state.terminalDevice, port);
Sudeep Desai5013f492020-01-08 16:01:47 +0530198 if (osnr <= OSNR_THRESHOLD_VALUE) {
199 log.error("Channel not possible for this OSNR Value : {}", osnr);
200 }
201 }
202 } else { // check if bitrate is greater than 100 Gig
203 modulation = ModulationScheme.DP_16QAM;
Sudeep Desaibffe1532020-01-21 16:43:46 +0530204 editConfig = state.modulationEditConfig(state.terminalDevice, port, component, bitRate, modulation.name());
Sudeep Desai5013f492020-01-08 16:01:47 +0530205 //setting the modulation by calling rpc
206 rpcResponse = state.setModulationRpc(port, component, editConfig);
207 if (rpcResponse) {
208 //TODO OSNR is valid only for receiver so need to modify
Sudeep Desaibffe1532020-01-21 16:43:46 +0530209 osnr = state.fetchDeviceSnr(state.terminalDevice, port);
Sudeep Desai5013f492020-01-08 16:01:47 +0530210 if (osnr <= OSNR_THRESHOLD_VALUE) {
211 modulation = ModulationScheme.DP_8QAM;
Sudeep Desaibffe1532020-01-21 16:43:46 +0530212 editConfig = state.modulationEditConfig(state.terminalDevice, port, component, bitRate,
Sudeep Desai5013f492020-01-08 16:01:47 +0530213 modulation.name());
214 //setting the modulation by calling rpc
215 rpcResponse = state.setModulationRpc(port, component, editConfig);
216 if (rpcResponse) {
217 // TODO OSNR is valid only for receiver so need to modify
Sudeep Desaibffe1532020-01-21 16:43:46 +0530218 osnr = state.fetchDeviceSnr(state.terminalDevice, port);
Sudeep Desai5013f492020-01-08 16:01:47 +0530219 if (osnr <= OSNR_THRESHOLD_VALUE) {
220 log.warn("Channel not possible for this OSNR Value : {}." +
221 " Please reduce the channel bitrate.", osnr);
222 }
223 }
224 }
225 }
226 }
227 }
228
229 public ModulationScheme modulationSchemeType(String modulationScheme) {
230 return ModulationScheme.valueOf(modulationScheme);
231 }
232
233 /**
234 * Get the target Modulation Scheme on the component.
235 *
236 * @param port the port
237 * @param component the port component
238 * @return ModulationScheme as per bitRate value
239 **/
240 @Override
241 public Optional<ModulationScheme> getModulationScheme(PortNumber port, T component) {
242 checkType(component);
243 return state.getModulationScheme(port, component);
244 }
245
246 /**
247 * Set the target Modulation Scheme on the component.
248 *
249 * @param port the port
250 * @param component the port component
251 * @param bitRate bit rate in bps
252 **/
253 @Override
254 public void setModulationScheme(PortNumber port, T component, long bitRate) {
255 checkType(component);
256 state.setModulationScheme(port, component, bitRate);
257 }
258
Sudeep Desaibffe1532020-01-21 16:43:46 +0530259 /**
260 * Get the Modulation Scheme on the component.
261 *
262 * @param conf HierarchicalConfiguration for path ../optical-channel/config
263 * @return Optional<ModulationScheme>
264 **/
265 public Optional<ModulationScheme> getModulation(XMLConfiguration conf) {
266 HierarchicalConfiguration config =
267 conf.configurationAt("components/component/optical-channel/config");
268
269 String modulationScheme = String.valueOf(config.getString("modulation"));
270
271 return Optional.of(modulationSchemeType(modulationScheme));
272 }
273
Sudeep Desai5013f492020-01-08 16:01:47 +0530274 /*
275 *
276 * Set the ComponentType to invoke proper methods for different template T.
277 * @param component the component.
278 */
279 void checkType(Object component) {
280 String clsName = component.getClass().getName();
281
282 if (component instanceof Direction) {
283 state = TerminalDeviceModulationConfig.ComponentType.DIRECTION;
284 } else if (component instanceof OchSignal) {
285 state = TerminalDeviceModulationConfig.ComponentType.OCHSIGNAL;
286 } else {
287 log.error("Cannot parse the component type {}.", clsName);
288 }
289
290
Sudeep Desaibffe1532020-01-21 16:43:46 +0530291 state.terminalDevice = this;
Sudeep Desai5013f492020-01-08 16:01:47 +0530292 }
293
294 /*
295 *
296 * Component type.
297 */
298
299
300 public enum ComponentType {
301
302 /*
303 *
304 * Direction.
305 */
306
307
308 DIRECTION() {
309 @Override
310 Optional<ModulationScheme> getModulationScheme(PortNumber port, Object component) {
311 return super.getModulationScheme(port, component);
312 }
313
314 @Override
315 void setModulationScheme(PortNumber port, Object component, long bitRate) {
316 super.setModulationScheme(port, component, bitRate);
317 }
318 },
319
320 /**
321 * OchSignal.
322 */
323
324
325 OCHSIGNAL() {
326 @Override
327 Optional<ModulationScheme> getModulationScheme(PortNumber port, Object component) {
328 return super.getModulationScheme(port, component);
329 }
330
331 @Override
332 void setModulationScheme(PortNumber port, Object component, long bitRate) {
333 super.setModulationScheme(port, component, bitRate);
334 }
335 };
336
337
Sudeep Desaibffe1532020-01-21 16:43:46 +0530338 TerminalDeviceModulationConfig terminalDevice;
Sudeep Desai5013f492020-01-08 16:01:47 +0530339
340 /*
341 * mirror method in the internal class.
342 * @param port port
343 * @param component component
344 * @return target modulation
345 */
346 Optional<ModulationScheme> getModulationScheme(PortNumber port, Object component) {
347 NetconfSession session = NetconfSessionUtility
Sudeep Desaibffe1532020-01-21 16:43:46 +0530348 .getNetconfSession(terminalDevice.getDeviceId(), terminalDevice.getController());
Sudeep Desai5013f492020-01-08 16:01:47 +0530349 checkNotNull(session);
Sudeep Desaibffe1532020-01-21 16:43:46 +0530350 String filter = createModulationFilter(terminalDevice, port);
Sudeep Desai5013f492020-01-08 16:01:47 +0530351 StringBuilder rpcReq = new StringBuilder();
352 rpcReq.append(RPC_TAG_NETCONF_BASE)
Sudeep Desaibffe1532020-01-21 16:43:46 +0530353 .append(terminalDevice.getModulationSchemeRequestRpc(filter))
Sudeep Desai5013f492020-01-08 16:01:47 +0530354 .append(RPC_CLOSE_TAG);
355 log.debug("RPC Call for Getting Modulation : \n {}", rpcReq.toString());
356 XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
357 if (xconf == null) {
358 log.error("Error in executingRpc");
359 return Optional.empty();
360 }
361 try {
Sudeep Desaibffe1532020-01-21 16:43:46 +0530362 return terminalDevice.getModulation(xconf);
Sudeep Desai5013f492020-01-08 16:01:47 +0530363 } catch (IllegalArgumentException e) {
364 return Optional.empty();
365 }
366 }
367
368 /*
369 * mirror method in the internal class.
370 * @param port port
371 * @param component component
372 * @param power target value
373 */
374 void setModulationScheme(PortNumber port, Object component, long bitRate) {
Sudeep Desaibffe1532020-01-21 16:43:46 +0530375 terminalDevice.setModulationSchemeProcessor(port, component, bitRate);
Sudeep Desai5013f492020-01-08 16:01:47 +0530376 }
377
378
379 /*
380 * Get filtered content under <optical-channel><state>.
381 * @param pc power config instance
382 * @param port the port number
383 * @param underState the filter condition
384 * @return RPC reply
385 */
386
387 //RPC call for OSNR still not finalised, need to update Rpc once validated
388 public static XMLConfiguration getTerminalDeviceSnr(TerminalDeviceModulationConfig config, PortNumber port) {
389 NetconfSession session = NetconfSessionUtility
390 .getNetconfSession(config.getDeviceId(), config.getController());
391 checkNotNull(session);
392 String name = ocName(config, port);
393 StringBuilder rpcReq = new StringBuilder(RPC_TAG_NETCONF_BASE);
394 rpcReq.append("<get><filter>")
395 .append("<osnr xmlns=\"http://openconfig.net/yang/terminal-device\">")
396 .append("<instant/>")
397 .append("</osnr></filter></get>")
398 .append(RPC_CLOSE_TAG);
399 log.info("RPC Call for Fetching OSNR :\n\n {}", rpcReq.toString());
400 XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
401 return xconf;
402 }
403
404 public static String createModulationFilter(TerminalDeviceModulationConfig modulationConfig,
405 PortNumber portNumber) {
406 String name = ocName(modulationConfig, portNumber);
407 StringBuilder sb = new StringBuilder("<components xmlns=\"http://openconfig.net/yang/platform\">");
408 sb.append("<component>")
409 .append(modulationConfig.createModulationFilterRequestRpc(name));
410 sb.append("</component>").append("</components>");
411 return sb.toString();
412 }
413
414 /**
415 * Extract component name from portNumber's annotations.
416 *
417 * @param pc modulation config instance
418 * @param portNumber the port number
419 * @return the component name
420 */
421
422
423 public static String ocName(TerminalDeviceModulationConfig pc, PortNumber portNumber) {
424 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
425 DeviceId deviceId = pc.handler().data().deviceId();
426 return deviceService.getPort(deviceId, portNumber).annotations().value("oc-name");
427 }
428
429 private static String channelSpacing(TerminalDeviceModulationConfig modulationConfig, PortNumber portNumber) {
430 DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
431 DeviceId deviceId = modulationConfig.handler().data().deviceId();
432 String lambda = deviceService.getPort(deviceId, portNumber).annotations().value("lambda");
433
434 ObjectMapper mapper = new ObjectMapper();
435 String channelSpacing = "";
436 try {
437 JsonNode actualObj = mapper.readTree(lambda);
438 JsonNode csNode = actualObj.get("channelSpacing");
439 channelSpacing = csNode.asText();
440 log.info("Channel_Spacing : " + channelSpacing);
441
442 } catch (IOException e) {
443 log.error("Error while parsing Json");
444 }
445 return channelSpacing;
446
447 }
448
449 private double fetchDeviceSnr(TerminalDeviceModulationConfig modulationConfig, PortNumber portNumber) {
450 double osnr = 0.0;
Sudeep Desaibffe1532020-01-21 16:43:46 +0530451 XMLConfiguration xconf = getTerminalDeviceSnr(terminalDevice, portNumber);
Sudeep Desai5013f492020-01-08 16:01:47 +0530452 if (xconf == null) {
453 return osnr;
454 }
455 try {
456 HierarchicalConfiguration config =
457 xconf.configurationAt("data/components/component/optical-channel/state/osnr");
458 osnr = Float.valueOf(config.getString("snr")).doubleValue();
459 return osnr;
460 } catch (IllegalArgumentException e) {
461 return osnr;
462 }
463 }
464 /*
465 *
466 * Parse filtering string from port and component.
467 * @param portNumber Port Number
468 * @param component port component (optical-channel)
469 * @param bitRate bitRate in bps
470 * @return filtering string in xml format
471
472 */
473
474 public String modulationEditConfig(TerminalDeviceModulationConfig modulationConfig, PortNumber portNumber,
475 Object component, long bitRate, String modulation) {
Sudeep Desaibffe1532020-01-21 16:43:46 +0530476 return terminalDevice.modulationEditConfigRequestRpc(modulationConfig, portNumber,
477 component, bitRate, modulation);
Sudeep Desai5013f492020-01-08 16:01:47 +0530478 }
479
480 public boolean setModulationRpc(PortNumber port, Object component, String editConfig) {
481 NetconfSession session = NetconfSessionUtility
Sudeep Desaibffe1532020-01-21 16:43:46 +0530482 .getNetconfSession(terminalDevice.getDeviceId(), terminalDevice.getController());
Sudeep Desai5013f492020-01-08 16:01:47 +0530483 checkNotNull(session);
484 boolean response = true;
485 StringBuilder rpcReq = new StringBuilder();
486 rpcReq.append(RPC_TAG_NETCONF_BASE)
487 .append("<edit-config>")
Sudeep Desaibffe1532020-01-21 16:43:46 +0530488 .append("<target><" + terminalDevice.getDataStoreId() + "/></target>")
Sudeep Desai5013f492020-01-08 16:01:47 +0530489 .append("<config>")
490 .append(editConfig)
491 .append("</config>")
492 .append("</edit-config>")
493 .append(RPC_CLOSE_TAG);
494 log.info("RPC call for Setting Modulation : {}", rpcReq.toString());
495 XMLConfiguration xconf = NetconfSessionUtility.executeRpc(session, rpcReq.toString());
496 if (xconf == null) {
497 log.error("The <edit-config> operation to set target-modulation of Port({}:{}) is failed.",
498 port.toString(), component.toString());
499 } else if (!xconf.getRoot().getChild(0).getName().equals("ok")) {
500 // The successful reply should be "<rpc-reply ...><ok /></rpc-reply>"
501 response = false;
502 log.error("The <edit-config> operation to set target-modulation of Port({}:{}) is failed.",
503 port.toString(), component.toString());
504 }
505 try {
506 session.commit();
507 } catch (NetconfException e) {
508 response = false;
509 log.error("error committing modulation changes");
510 }
511 return response;
512 }
513 }
514
515
516}