blob: 9f23f7b86d74571c0c455eb9429aa038c399c1c4 [file] [log] [blame]
10068695e340ec92019-10-11 07:03:00 +00001/*
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 */
16package org.onosproject.drivers.zte;
17
18import com.google.common.collect.ImmutableList;
19import com.google.common.io.CharSource;
20import org.apache.commons.configuration.HierarchicalConfiguration;
21import org.apache.commons.configuration.XMLConfiguration;
22import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
23import org.onlab.packet.ChassisId;
24import org.onosproject.drivers.utilities.XmlConfigParser;
25import org.onosproject.net.ChannelSpacing;
26import org.onosproject.net.DefaultAnnotations;
27import org.onosproject.net.Device;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.OchSignal;
30import org.onosproject.net.OduSignalType;
31import org.onosproject.net.Port.Type;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.device.DefaultDeviceDescription;
34import org.onosproject.net.device.DefaultPortDescription;
35import org.onosproject.net.device.DefaultPortDescription.Builder;
36import org.onosproject.net.device.DeviceDescription;
37import org.onosproject.net.device.DeviceDescriptionDiscovery;
38import org.onosproject.net.device.PortDescription;
39import org.onosproject.net.driver.AbstractHandlerBehaviour;
40import org.onosproject.net.optical.device.OchPortHelper;
41import org.onosproject.netconf.NetconfController;
42import org.onosproject.netconf.NetconfException;
43import org.onosproject.netconf.NetconfSession;
44import org.onosproject.odtn.behaviour.OdtnDeviceDescriptionDiscovery;
45import org.onosproject.net.AnnotationKeys;
46import org.slf4j.Logger;
47
48import java.util.HashMap;
49import java.util.List;
50import java.util.Map;
51import java.util.Objects;
52import java.util.stream.Collectors;
53
54import static org.slf4j.LoggerFactory.getLogger;
55
56public class ZteDeviceDiscoveryImpl
57 extends AbstractHandlerBehaviour
58 implements OdtnDeviceDescriptionDiscovery, DeviceDescriptionDiscovery {
59 private final Logger log = getLogger(getClass());
60
61 @Override
62 public DeviceDescription discoverDeviceDetails() {
63 DeviceId deviceId = handler().data().deviceId();
64 log.info("Discovering ZTE device {}", deviceId);
65
66 NetconfController controller = handler().get(NetconfController.class);
67 NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
68
69 String hwVersion = "ZTE hw";
70 String swVersion = "ZTE sw";
71 String serialNumber = "000000000000";
72
73 try {
74 String reply = session.requestSync(buildDeviceInfoRequest());
75 XMLConfiguration cfg = (XMLConfiguration) XmlConfigParser.loadXmlString(getDataOfRpcReply(reply));
76 hwVersion = cfg.getString("components.component.state.hardware-version");
77 swVersion = cfg.getString("components.component.state.software-version");
78 serialNumber = cfg.getString("components.component.state.serial-no");
79 } catch (NetconfException e) {
80 log.error("ZTE device discovery error.", e);
81 }
82
83 return new DefaultDeviceDescription(deviceId.uri(),
84 Device.Type.OTN,
85 "ZTE",
86 hwVersion,
87 swVersion,
88 serialNumber,
89 new ChassisId(1));
90 }
91
92 private String buildDeviceInfoRequest() {
93 StringBuilder rpc = new StringBuilder();
94 rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
95 rpc.append("<get>");
96 rpc.append("<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">");
97 rpc.append("<components xmlns=\"http://openconfig.net/yang/platform\">");
98 rpc.append("<component>");
99 rpc.append("<name>CHASSIS-1-1</name>");
100 rpc.append("<state></state>");
101 rpc.append("</component>");
102 rpc.append("</components>");
103 rpc.append("</filter>");
104 rpc.append("</get>");
105 rpc.append("</rpc>");
106
107 return rpc.toString();
108 }
109
110 private String getDataOfRpcReply(String rpcReply) {
111 String data = null;
112 int begin = rpcReply.indexOf("<data>");
113 int end = rpcReply.lastIndexOf("</data>");
114 if (begin != -1 && end != -1) {
115 data = (String) rpcReply.subSequence(begin, end + "</data>".length());
116 } else {
117 data = rpcReply;
118 }
119 return data;
120 }
121
122 @Override
123 public List<PortDescription> discoverPortDetails() {
124 DeviceId deviceId = handler().data().deviceId();
125 log.info("Discovering ZTE device ports {}", deviceId);
126
127 NetconfController controller = handler().get(NetconfController.class);
128 NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
129 XMLConfiguration cfg = new XMLConfiguration();
130 try {
131 String reply = session.requestSync(buildPortDetailRequest(), 30);
132 String data = getDataOfRpcReply(reply);
133 if (data == null) {
134 log.error("No valid response found from {}:\n{}", deviceId, reply);
135 return ImmutableList.of();
136 }
137 cfg.load(CharSource.wrap(data).openStream());
138 return discoverPorts(cfg);
139 } catch (Exception e) {
140 log.error("ZTE device port discovery error.", e);
141 }
142
143 return ImmutableList.of();
144 }
145
146 private String buildPortDetailRequest() {
147 StringBuilder rpc = new StringBuilder();
148 rpc.append("<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
149 rpc.append("<get>");
150 rpc.append("<filter xmlns:ns0=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ns0:type=\"subtree\">");
151 rpc.append("<components xmlns=\"http://openconfig.net/yang/platform\">");
152 rpc.append("</components>");
153 rpc.append("</filter>");
154 rpc.append("</get>");
155 rpc.append("</rpc>");
156
157 return rpc.toString();
158 }
159
160 private List<PortDescription> discoverPorts(XMLConfiguration cfg) {
161 cfg.setExpressionEngine(new XPathExpressionEngine());
162 List<HierarchicalConfiguration> components = cfg.configurationsAt("components/component");
163 return components.stream()
164 .filter(this::isPortComponent)
165 .map(this::toPortDescriptionInternal)
166 .filter(Objects::nonNull)
167 .collect(Collectors.toList());
168 }
169
170 private boolean isPortComponent(HierarchicalConfiguration component) {
171 String name = component.getString("name");
172 String type = component.getString("state/type");
173
174 return name != null && name.startsWith("PORT") && type != null
175 && type.equals("openconfig-platform-types:PORT");
176 }
177
178 private PortDescription toPortDescriptionInternal(HierarchicalConfiguration component) {
179 Map<String, String> annotations = new HashMap<>();
180 String name = component.getString("name");
181 String type = component.getString("state/type");
182
183 annotations.put(OdtnDeviceDescriptionDiscovery.OC_NAME, name);
184 annotations.put(OdtnDeviceDescriptionDiscovery.OC_TYPE, type);
185 annotations.putIfAbsent(AnnotationKeys.PORT_NAME, name);
186
187 // PORT-1-4-C1
188 String[] textStr = name.split("-");
189
190 // use different value of portNumber on the same equipment
191 String portComponentIndex = textStr[textStr.length - 1];
192 int slotIndex = Integer.parseInt(textStr[2]);
193 int slotPortIndex = Integer.parseInt(portComponentIndex.substring(1));
194 int portNumber = slotIndex * 10 + slotPortIndex;
195
196 annotations.putIfAbsent(ONOS_PORT_INDEX, portComponentIndex);
197 annotations.putIfAbsent(CONNECTION_ID, "connection:" + Integer.parseInt(portComponentIndex.substring(1)));
198
199 if (portComponentIndex.charAt(0) == 'L') {
200 // line
201 annotations.putIfAbsent(PORT_TYPE, OdtnPortType.LINE.value());
202 OchSignal signalId = OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1);
203 return OchPortHelper.ochPortDescription(
204 PortNumber.portNumber(portNumber + 100L),
205 true,
206 OduSignalType.ODUC2,
207 true,
208 signalId,
209 DefaultAnnotations.builder().putAll(annotations).build());
210 } else if (portComponentIndex.charAt(0) == 'C') {
211 // client
212 annotations.putIfAbsent(PORT_TYPE, OdtnPortType.CLIENT.value());
213 Builder builder = DefaultPortDescription.builder();
214 builder.withPortNumber(PortNumber.portNumber(portNumber))
215 .isEnabled(true)
216 .portSpeed(100000L)
217 .type(Type.PACKET)
218 .annotations(DefaultAnnotations.builder().putAll(annotations).build());
219
220 return builder.build();
221 }
222
223 return null;
224 }
225}