2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.troubleshoot.web;
11 import java.net.InetAddress;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Date;
15 import java.util.HashMap;
16 import java.util.List;
20 import javax.servlet.http.HttpServletRequest;
22 import org.opendaylight.controller.sal.action.Action;
23 import org.opendaylight.controller.sal.action.Output;
24 import org.opendaylight.controller.sal.action.SetVlanId;
25 import org.opendaylight.controller.sal.authorization.Privilege;
26 import org.opendaylight.controller.sal.authorization.UserLevel;
27 import org.opendaylight.controller.sal.core.Description;
28 import org.opendaylight.controller.sal.core.Node;
29 import org.opendaylight.controller.sal.core.NodeConnector;
30 import org.opendaylight.controller.sal.core.TimeStamp;
31 import org.opendaylight.controller.sal.flowprogrammer.Flow;
32 import org.opendaylight.controller.sal.match.Match;
33 import org.opendaylight.controller.sal.match.MatchType;
34 import org.opendaylight.controller.sal.reader.FlowOnNode;
35 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
36 import org.opendaylight.controller.sal.utils.EtherTypes;
37 import org.opendaylight.controller.sal.utils.GlobalConstants;
38 import org.opendaylight.controller.sal.utils.HexEncode;
39 import org.opendaylight.controller.sal.utils.IPProtocols;
40 import org.opendaylight.controller.sal.utils.NetUtils;
41 import org.opendaylight.controller.sal.utils.ServiceHelper;
42 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
43 import org.opendaylight.controller.switchmanager.ISwitchManager;
44 import org.opendaylight.controller.web.DaylightWebUtil;
45 import org.opendaylight.controller.web.IDaylightWeb;
46 import org.springframework.stereotype.Controller;
47 import org.springframework.web.bind.annotation.RequestMapping;
48 import org.springframework.web.bind.annotation.RequestMethod;
49 import org.springframework.web.bind.annotation.RequestParam;
50 import org.springframework.web.bind.annotation.ResponseBody;
54 public class Troubleshoot implements IDaylightWeb {
55 private static final UserLevel AUTH_LEVEL = UserLevel.CONTAINERUSER;
56 private static final List<String> flowStatsColumnNames = Arrays.asList("Node", "In Port",
57 "DL Src", "DL Dst", "DL Type", "DL Vlan", "NW Src", "NW Dst",
58 "NW Proto", "TP Src", "TP Dst", "Actions", "Bytes", "Packets",
59 "Time (s)", "Timeout (s)", "Out Port(s)", "Out Vlan",
61 private static final List<String> portStatsColumnNames = Arrays.asList("Node Connector",
62 "Rx Pkts", "Tx Pkts", "Rx Bytes", "Tx Bytes", "Rx Drops",
63 "Tx Drops", "Rx Errs", "Tx Errs", "Rx Frame Errs",
64 "Rx OverRun Errs", "Rx CRC Errs", "Collisions");
65 private static final List<String> nodesColumnNames = Arrays.asList("Node", "Node ID", "Statistics");
66 private static final List<String> nodeStatsColumnNames = Arrays.asList("Node", "Node ID", "Statistics");
67 private final String WEB_NAME = "Troubleshoot";
68 private final String WEB_ID = "troubleshoot";
69 private final short WEB_ORDER = 4;
72 public Troubleshoot() {
73 ServiceHelper.registerGlobalService(IDaylightWeb.class, this, null);
77 public String getWebName() {
82 public String getWebId() {
87 public short getWebOrder() {
92 public boolean isAuthorized(UserLevel userLevel) {
93 return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
96 @RequestMapping(value = "/existingNodes", method = RequestMethod.GET)
98 public TroubleshootingJsonBean getExistingNodes(HttpServletRequest request, @RequestParam(required = false) String container) {
99 List<Map<String, String>> lines = new ArrayList<Map<String, String>>();
100 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
102 // Derive the privilege this user has on the current container
103 String userName = request.getUserPrincipal().getName();
104 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
106 if (privilege != Privilege.NONE) {
107 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
108 .getInstance(ISwitchManager.class, containerName, this);
109 Set<Node> nodeSet = (switchManager != null) ? switchManager.getNodes() : null;
110 if (nodeSet != null) {
111 for (Node node : nodeSet) {
112 Map<String, String> device = new HashMap<String, String>();
113 device.put("nodeName", getNodeDesc(node, switchManager));
114 device.put("nodeId", node.toString());
120 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
121 result.setColumnNames(nodesColumnNames);
122 result.setNodeData(lines);
126 @RequestMapping(value = "/uptime", method = RequestMethod.GET)
128 public TroubleshootingJsonBean getUptime(HttpServletRequest request, @RequestParam(required = false) String container) {
129 List<Map<String, String>> lines = new ArrayList<Map<String, String>>();
130 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
132 // Derive the privilege this user has on the current container
133 String userName = request.getUserPrincipal().getName();
134 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
136 if (privilege != Privilege.NONE) {
137 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
138 .getInstance(ISwitchManager.class, containerName, this);
139 Set<Node> nodeSet = (switchManager != null) ? switchManager.getNodes() : null;
140 if (nodeSet != null) {
141 for (Node node : nodeSet) {
142 Map<String, String> device = new HashMap<String, String>();
143 device.put("nodeName", getNodeDesc(node, switchManager));
144 device.put("nodeId", node.toString());
145 TimeStamp timeStamp = (TimeStamp) switchManager.getNodeProp(
146 node, TimeStamp.TimeStampPropName);
147 Long time = (timeStamp == null) ? 0 : timeStamp.getValue();
148 String date = (time == 0) ? "" : (new Date(time)).toString();
149 device.put("connectedSince", date);
155 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
156 result.setColumnNames(nodeStatsColumnNames);
157 result.setNodeData(lines);
161 @RequestMapping(value = "/flowStats", method = RequestMethod.GET)
163 public TroubleshootingJsonBean getFlowStats(
164 @RequestParam("nodeId") String nodeId,
165 HttpServletRequest request, @RequestParam(required = false) String container) {
166 List<Map<String, String>> cells = new ArrayList<Map<String, String>>();
167 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
169 // Derive the privilege this user has on the current container
170 String userName = request.getUserPrincipal().getName();
171 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
173 if (privilege != Privilege.NONE) {
174 IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
175 .getInstance(IStatisticsManager.class, containerName, this);
176 if (statisticsManager != null) {
177 Node node = Node.fromString(nodeId);
178 List<FlowOnNode> statistics = statisticsManager.getFlows(node);
179 for (FlowOnNode stats : statistics) {
180 cells.add(this.convertFlowStatistics(node, stats, containerName));
185 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
186 result.setColumnNames(flowStatsColumnNames);
187 result.setNodeData(cells);
191 @RequestMapping(value = "/portStats", method = RequestMethod.GET)
193 public TroubleshootingJsonBean getPortStats(
194 @RequestParam("nodeId") String nodeId,
195 HttpServletRequest request, @RequestParam(required = false) String container) {
196 List<Map<String, String>> cells = new ArrayList<Map<String, String>>();
197 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
199 // Derive the privilege this user has on the current container
200 String userName = request.getUserPrincipal().getName();
201 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
203 if (privilege != Privilege.NONE) {
204 IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
205 .getInstance(IStatisticsManager.class, containerName, this);
206 if (statisticsManager != null) {
207 Node node = Node.fromString(nodeId);
208 List<NodeConnectorStatistics> statistics = statisticsManager
209 .getNodeConnectorStatistics(node);
210 for (NodeConnectorStatistics stats : statistics) {
211 cells.add(this.convertPortsStatistics(stats, containerName));
216 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
217 result.setColumnNames(portStatsColumnNames);
218 result.setNodeData(cells);
222 private Map<String, String> convertPortsStatistics(
223 NodeConnectorStatistics ncStats, String containerName) {
224 Map<String, String> row = new HashMap<String, String>();
226 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
227 .getInstance(ISwitchManager.class, containerName, this);
228 NodeConnector nodeConnector = ncStats.getNodeConnector();
229 Description description = (Description) switchManager.getNodeProp(nodeConnector.getNode(), Description.propertyName);
230 String desc = (description == null) ? "" : description.getValue();
231 String nodeName = desc.equalsIgnoreCase("none") ? nodeConnector.getNode().getNodeIDString() : desc;
232 String nodeConnectorDisplayName = nodeConnector.getType() + "|" + nodeConnector.getID() + "@" + nodeName;
233 row.put("nodeConnector",
234 String.valueOf(nodeConnectorDisplayName));
236 row.put("rxPkts", String.valueOf(ncStats.getReceivePacketCount()));
237 row.put("txPkts", String.valueOf(ncStats.getTransmitPacketCount()));
238 row.put("rxBytes", String.valueOf(ncStats.getReceiveByteCount()));
239 row.put("txBytes", String.valueOf(ncStats.getTransmitByteCount()));
240 row.put("rxDrops", String.valueOf(ncStats.getReceiveDropCount()));
241 row.put("txDrops", String.valueOf(ncStats.getTransmitDropCount()));
242 row.put("rxErrors", String.valueOf(ncStats.getReceiveErrorCount()));
243 row.put("txErrors", String.valueOf(ncStats.getTransmitErrorCount()));
244 row.put("rxFrameErrors",
245 String.valueOf(ncStats.getReceiveFrameErrorCount()));
246 row.put("rxOverRunErrors",
247 String.valueOf(ncStats.getReceiveOverRunErrorCount()));
248 row.put("rxCRCErrors",
249 String.valueOf(ncStats.getReceiveCRCErrorCount()));
250 row.put("collisions", String.valueOf(ncStats.getCollisionCount()));
255 private Map<String, String> convertFlowStatistics(Node node,
256 FlowOnNode flowOnNode,
257 String containerName) {
258 Map<String, String> row = new HashMap<String, String>();
259 Flow flow = flowOnNode.getFlow();
260 Match match = flow.getMatch();
261 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
262 .getInstance(ISwitchManager.class, containerName, this);
263 String desc = getNodeDesc(node, switchManager);
264 desc = (desc == null || desc.isEmpty() || desc.equalsIgnoreCase("none"))?
265 node.toString() : desc;
266 row.put("nodeName", desc);
267 if (match.isPresent(MatchType.IN_PORT)) {
268 row.put(MatchType.IN_PORT.id(), ((NodeConnector) flow.getMatch()
269 .getField(MatchType.IN_PORT).getValue())
270 .getNodeConnectorIdAsString());
272 row.put(MatchType.IN_PORT.id(), "*");
274 if (match.isPresent(MatchType.DL_SRC)) {
275 row.put(MatchType.DL_SRC.id(),
276 (HexEncode.bytesToHexString(((byte[]) flow.getMatch()
277 .getField(MatchType.DL_SRC).getValue()))));
279 row.put(MatchType.DL_SRC.id(), "*");
281 if (match.isPresent(MatchType.DL_DST)) {
282 row.put(MatchType.DL_DST.id(),
283 (HexEncode.bytesToHexString(((byte[]) flow.getMatch()
284 .getField(MatchType.DL_DST).getValue()))));
286 row.put(MatchType.DL_DST.id(), "*");
288 if (match.isPresent(MatchType.DL_TYPE)) {
289 row.put(MatchType.DL_TYPE.id(),
290 EtherTypes.getEtherTypeName(((Short) flow.getMatch()
291 .getField(MatchType.DL_TYPE).getValue())));
293 row.put(MatchType.DL_TYPE.id(), "*");
296 // Some physical switch has vlan as ffff to show "any" vlan
297 if (match.isPresent(MatchType.DL_VLAN)) {
298 if (((Short) flow.getMatch().getField(MatchType.DL_VLAN).getValue())
300 row.put(MatchType.DL_VLAN.id(), "0");
302 row.put(MatchType.DL_VLAN.id(), ((Short) flow.getMatch()
303 .getField(MatchType.DL_VLAN).getValue()).toString());
306 row.put(MatchType.DL_VLAN.id(), "*");
308 if (match.isPresent(MatchType.NW_SRC)) {
309 row.put(MatchType.NW_SRC.id(), ((InetAddress) flow.getMatch()
310 .getField(MatchType.NW_SRC).getValue()).getHostAddress());
312 row.put(MatchType.NW_SRC.id(), "*");
314 if (match.isPresent(MatchType.NW_DST)) {
315 row.put(MatchType.NW_DST.id(), ((InetAddress) flow.getMatch()
316 .getField(MatchType.NW_DST).getValue()).getHostAddress());
318 row.put(MatchType.NW_DST.id(), "*");
320 if (match.isPresent(MatchType.NW_PROTO)) {
321 row.put(MatchType.NW_PROTO.id(),
322 IPProtocols.getProtocolName(((Byte) flow.getMatch()
323 .getField(MatchType.NW_PROTO).getValue())));
325 row.put(MatchType.NW_PROTO.id(), "*");
327 if (match.isPresent(MatchType.TP_SRC)) {
328 Short tpSrc = (Short) (flow.getMatch().getField(MatchType.TP_SRC)
330 row.put(MatchType.TP_SRC.id(),
331 String.valueOf(NetUtils.getUnsignedShort(tpSrc)));
333 row.put(MatchType.TP_SRC.id(), "*");
335 if (match.isPresent(MatchType.TP_DST)) {
336 Short tpDst = (Short) (flow.getMatch().getField(MatchType.TP_DST)
338 row.put(MatchType.TP_DST.id(),
339 String.valueOf(NetUtils.getUnsignedShort(tpDst)));
341 row.put(MatchType.TP_DST.id(), "*");
344 row.put("byteCount", ((Long) flowOnNode.getByteCount()).toString());
345 row.put("packetCount", ((Long) flowOnNode.getPacketCount()).toString());
347 StringBuffer actions = new StringBuffer();
348 StringBuffer outPorts = new StringBuffer();
349 String outVlanId = null;
350 for (Action action : flow.getActions()) {
351 actions.append(action.getType().toString() + "\n");
352 if (action instanceof Output) {
353 Output ao = (Output) action;
354 if (outPorts.length() > 0) {
355 outPorts.append(" ");
357 outPorts.append(ao.getPort().getNodeConnectorIdAsString());
358 } else if (action instanceof SetVlanId) {
359 SetVlanId av = (SetVlanId) action;
360 outVlanId = String.valueOf(av.getVlanId());
363 if (outPorts.length() == 0) {
364 outPorts.append("*");
366 if (outVlanId == null) {
369 row.put("actions", actions.toString());
370 row.put("outPorts", outPorts.toString());
371 row.put("outVlanId", outVlanId);
372 row.put("durationSeconds",
373 ((Integer) flowOnNode.getDurationSeconds()).toString());
374 row.put("idleTimeout", ((Short) flow.getIdleTimeout()).toString());
375 row.put("priority", String.valueOf(flow.getPriority()));
379 private String getNodeDesc(Node node, ISwitchManager switchManager) {
380 if (switchManager == null) {
383 Description desc = (Description) switchManager.getNodeProp(node, Description.propertyName);
384 return (desc == null) ? "" : desc.getValue();