blob: 70013827cc8fc71c2532f781ac71f27272494403 [file] [log] [blame]
David Bainbridge7526c452018-04-20 14:14:37 -07001/*
2 * Copyright 2018-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.ciena.c5162.netconf;
17
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.util.ArrayList;
22import java.util.Collection;
23import java.util.HashMap;
24import java.util.HashSet;
25import java.util.List;
26import java.util.Map;
27import java.util.Set;
28
29import javax.xml.xpath.XPath;
30import javax.xml.xpath.XPathConstants;
31import javax.xml.xpath.XPathExpressionException;
32import javax.xml.xpath.XPathFactory;
33
34import org.onlab.packet.ChassisId;
35import org.onosproject.drivers.netconf.TemplateManager;
36import org.onosproject.net.ConnectPoint;
37import org.onosproject.net.Device;
38import org.onosproject.net.DeviceId;
39import org.onosproject.net.Link;
40import org.onosproject.net.Port;
41import org.onosproject.net.PortNumber;
42import org.onosproject.net.behaviour.LinkDiscovery;
43import org.onosproject.net.device.DefaultDeviceDescription;
44import org.onosproject.net.device.DefaultPortDescription;
45import org.onosproject.net.device.DefaultPortStatistics;
46import org.onosproject.net.device.DeviceDescription;
47import org.onosproject.net.device.DeviceDescriptionDiscovery;
48import org.onosproject.net.device.DeviceService;
49import org.onosproject.net.device.PortDescription;
50import org.onosproject.net.device.PortStatistics;
51import org.onosproject.net.device.PortStatisticsDiscovery;
52import org.onosproject.net.driver.AbstractHandlerBehaviour;
53import org.onosproject.net.link.DefaultLinkDescription;
54import org.onosproject.net.link.LinkDescription;
55import org.onosproject.netconf.NetconfController;
56import org.onosproject.netconf.NetconfException;
57import org.onosproject.netconf.NetconfSession;
58import org.slf4j.Logger;
59import org.w3c.dom.Node;
60import org.w3c.dom.NodeList;
61
62/**
63 * Discovers the ports from a Ciena WaveServer Rest device.
64 */
65public class Ciena5162DeviceDescription extends AbstractHandlerBehaviour
66 implements DeviceDescriptionDiscovery, PortStatisticsDiscovery, LinkDiscovery {
67 private static final Logger log = getLogger(Ciena5162DeviceDescription.class);
68 private static final TemplateManager TEMPLATE_MANAGER = new TemplateManager();
69
70 static {
71 TEMPLATE_MANAGER.load(Ciena5162DeviceDescription.class, "/templates/requests/%s.j2", "systemInfo",
72 "softwareVersion", "logicalPorts", "port-stats", "link-info");
73 }
74
75 @Override
76 public DeviceDescription discoverDeviceDetails() {
77
78 DeviceId deviceId = handler().data().deviceId();
79 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
80 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
81 try {
82 Node systemInfo = TEMPLATE_MANAGER.doRequest(session, "systemInfo");
83 Node softwareVersion = TEMPLATE_MANAGER.doRequest(session, "softwareVersion");
84 XPath xp = XPathFactory.newInstance().newXPath();
85 String mac = xp.evaluate("components/component/properties/property/state/value/text()", systemInfo)
86 .toUpperCase();
87 return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH,
88 xp.evaluate("components/component/state/mfg-name/text()", systemInfo),
89 xp.evaluate("components/component/state/name/text()", systemInfo),
90 xp.evaluate("software-state/running-package/package-version/text()", softwareVersion),
91 xp.evaluate("components/component/state/serial-no/text()", systemInfo),
92 new ChassisId(Long.valueOf(mac, 16)));
93
94 } catch (XPathExpressionException | NetconfException ne) {
95 log.error("failed to query system info from device {}", handler().data().deviceId(), ne);
96 }
97
98 return new DefaultDeviceDescription(deviceId.uri(), Device.Type.SWITCH, "Ciena", "5162", "Unknown", "Unknown",
99 new ChassisId());
100 }
101
102 /**
103 * Convert the specification of port speed in the of of #unit, i.e. {@10G} to MB
104 * as represented by a Long.
105 *
106 * @param ps
107 * specification of port speed
108 * @return port speed as MBs
109 */
110 private Long portSpeedToLong(String ps) {
111 String value = ps.trim();
112 StringBuilder digits = new StringBuilder();
113 String unit = "";
114 for (int i = 0; i < value.length(); i += 1) {
115 final char c = value.charAt(i);
116 if (Character.isDigit(c)) {
117 digits.append(c);
118 } else {
119 unit = value.substring(i).toUpperCase().trim();
120 break;
121 }
122 }
123
124 switch (unit) {
125 case "G":
126 case "GB":
127 return Long.valueOf(digits.toString()) * 1000;
128 case "M":
129 case "MB":
130 default:
131 return Long.valueOf(digits.toString());
132 }
133 }
134
135 @Override
136 public List<PortDescription> discoverPortDetails() {
137 List<PortDescription> ports = new ArrayList<PortDescription>();
138 DeviceId deviceId = handler().data().deviceId();
139 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
140 if (controller == null || controller.getDevicesMap() == null
141 || controller.getDevicesMap().get(deviceId) == null) {
142 log.warn("NETCONF session to device {} not yet established, will be retried", deviceId);
143 return ports;
144 }
145 NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
146
147 try {
148 Node logicalPorts = TEMPLATE_MANAGER.doRequest(session, "logicalPorts");
149 XPath xp = XPathFactory.newInstance().newXPath();
150 NodeList nl = (NodeList) xp.evaluate("interfaces/interface/config", logicalPorts, XPathConstants.NODESET);
151 int count = nl.getLength();
152 Node node;
153 for (int i = 0; i < count; i += 1) {
154 node = nl.item(i);
155 if (xp.evaluate("type/text()", node).equals("ettp")) {
156 ports.add(DefaultPortDescription.builder()
157 .withPortNumber(PortNumber.portNumber(xp.evaluate("name/text()", node)))
158 .isEnabled(Boolean.valueOf(xp.evaluate("admin-status/text()", node)))
159 .portSpeed(portSpeedToLong(xp.evaluate("port-speed/text()", node))).type(Port.Type.PACKET)
160 .build());
161 }
162 }
163 } catch (NetconfException | XPathExpressionException e) {
164 log.error("Unable to retrieve port information for device {}, {}", deviceId, e);
165 }
166 return ports;
167 }
168
169 @Override
170 public Collection<PortStatistics> discoverPortStatistics() {
171 List<PortStatistics> stats = new ArrayList<PortStatistics>();
172
173 DeviceId deviceId = handler().data().deviceId();
174 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
175 if (controller == null || controller.getDevicesMap() == null
176 || controller.getDevicesMap().get(deviceId) == null) {
177 log.warn("NETCONF session to device {} not yet established, will be retried", deviceId);
178 return stats;
179 }
180 NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
181
182 try {
183 Node data = TEMPLATE_MANAGER.doRequest(session, "port-stats");
184 XPath xp = XPathFactory.newInstance().newXPath();
185 NodeList interfaces = (NodeList) xp.evaluate("interfaces/interface", data, XPathConstants.NODESET);
186 int count = interfaces.getLength();
187 for (int i = 0; i < count; i += 1) {
188 Node iface = interfaces.item(i);
189 if (xp.evaluate("config/type/text()", iface).equals("ettp")) {
190 stats.add(DefaultPortStatistics.builder().setDeviceId(deviceId)
191 .setPort(PortNumber.portNumber(xp.evaluate("name/text()", iface)))
192 .setBytesReceived(Long.valueOf(xp.evaluate("state/counters/in-octets/text()", iface)))
193 .setBytesSent(Long.valueOf(xp.evaluate("state/counters/out-octets/text()", iface)))
194 .setPacketsReceived(Long.valueOf(xp.evaluate("state/counters/in-pkts/text()", iface)))
195 .setPacketsSent(Long.valueOf(xp.evaluate("state/counters/out-pkts/text()", iface)))
196 .setPacketsTxErrors(Long.valueOf(xp.evaluate("state/counters/out-errors/text()", iface)))
197 .setPacketsRxErrors(Long.valueOf(xp.evaluate("state/counters/in-errors/text()", iface)))
198 .build());
199 }
200 }
201 } catch (NetconfException | XPathExpressionException e) {
202 log.error("Unable to retrieve port statistics for device {}, {}", deviceId, e);
203 }
204
205 return stats;
206 }
207
208 @Override
209 public Set<LinkDescription> getLinks() {
210 log.debug("LINKS CHECKING ...");
211 Set<LinkDescription> links = new HashSet<LinkDescription>();
212 DeviceId deviceId = handler().data().deviceId();
213 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
214 if (controller == null || controller.getDevicesMap() == null
215 || controller.getDevicesMap().get(deviceId) == null) {
216 log.warn("NETCONF session to device {} not yet established, cannot load links, will be retried", deviceId);
217 return links;
218 }
219 NetconfSession session = controller.getDevicesMap().get(deviceId).getSession();
220 try {
221
222 DeviceService deviceService = this.handler().get(DeviceService.class);
223
224 Iterable<Device> devices = deviceService.getAvailableDevices();
225 Map<String, Device> lookup = new HashMap<String, Device>();
226 for (Device d : devices) {
227 lookup.put(d.chassisId().toString().toUpperCase(), d);
228 }
229
230 Node logicalPorts = TEMPLATE_MANAGER.doRequest(session, "link-info");
231 XPath xp = XPathFactory.newInstance().newXPath();
232 NodeList ifaces = (NodeList) xp.evaluate("interfaces/interface", logicalPorts, XPathConstants.NODESET);
233 int count = ifaces.getLength();
234 Node iface;
235 Node destChassis;
236 for (int i = 0; i < count; i += 1) {
237 iface = ifaces.item(i);
238 if (xp.evaluate("config/type/text()", iface).equals("ettp")) {
239 destChassis = (Node) xp.evaluate("state/lldp-remote-port-operational/chassis-id", iface,
240 XPathConstants.NODE);
241
242 if (destChassis != null) {
243 Device dest = lookup.get(destChassis.getTextContent().toUpperCase());
244
245 if (dest != null) {
246
247 links.add(new DefaultLinkDescription(
248 new ConnectPoint(deviceId,
249 PortNumber.portNumber(xp.evaluate("name/text()", iface))),
250 new ConnectPoint(dest.id(),
251 PortNumber.portNumber(xp.evaluate(
252 "state/lldp-remote-port-operational/port-id/text()", iface))),
253 Link.Type.DIRECT, true));
254 } else {
Jeff Groom34c28ce2018-04-26 19:42:18 -0600255 log.warn("DEST chassisID not found: chassis {} port {}",
256 destChassis.getTextContent().toUpperCase(), xp.evaluate("name/text()", iface));
David Bainbridge7526c452018-04-20 14:14:37 -0700257 }
258 } else {
259 log.debug("NO LINK for {}", xp.evaluate("name/text()", iface));
260 }
261 }
262 }
263 } catch (NetconfException | XPathExpressionException e) {
264 log.error("Unable to retrieve links for device {}, {}", deviceId, e);
265 }
266
267 return links;
268 }
269
270}