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));
216 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
217 result.setColumnNames(portStatsColumnNames);
218 result.setNodeData(cells);
222 private Map<String, String> convertPortsStatistics(
223 NodeConnectorStatistics ncStats) {
224 Map<String, String> row = new HashMap<String, String>();
226 row.put("nodeConnector",
227 String.valueOf(ncStats.getNodeConnector().toString()));
228 row.put("rxPkts", String.valueOf(ncStats.getReceivePacketCount()));
229 row.put("txPkts", String.valueOf(ncStats.getTransmitPacketCount()));
230 row.put("rxBytes", String.valueOf(ncStats.getReceiveByteCount()));
231 row.put("txBytes", String.valueOf(ncStats.getTransmitByteCount()));
232 row.put("rxDrops", String.valueOf(ncStats.getReceiveDropCount()));
233 row.put("txDrops", String.valueOf(ncStats.getTransmitDropCount()));
234 row.put("rxErrors", String.valueOf(ncStats.getReceiveErrorCount()));
235 row.put("txErrors", String.valueOf(ncStats.getTransmitErrorCount()));
236 row.put("rxFrameErrors",
237 String.valueOf(ncStats.getReceiveFrameErrorCount()));
238 row.put("rxOverRunErrors",
239 String.valueOf(ncStats.getReceiveOverRunErrorCount()));
240 row.put("rxCRCErrors",
241 String.valueOf(ncStats.getReceiveCRCErrorCount()));
242 row.put("collisions", String.valueOf(ncStats.getCollisionCount()));
247 private Map<String, String> convertFlowStatistics(Node node,
248 FlowOnNode flowOnNode,
249 String containerName) {
250 Map<String, String> row = new HashMap<String, String>();
251 Flow flow = flowOnNode.getFlow();
252 Match match = flow.getMatch();
253 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
254 .getInstance(ISwitchManager.class, containerName, this);
255 String desc = getNodeDesc(node, switchManager);
256 desc = (desc == null || desc.isEmpty() || desc.equalsIgnoreCase("none"))?
257 node.toString() : desc;
258 row.put("nodeName", desc);
259 if (match.isPresent(MatchType.IN_PORT)) {
260 row.put(MatchType.IN_PORT.id(), ((NodeConnector) flow.getMatch()
261 .getField(MatchType.IN_PORT).getValue())
262 .getNodeConnectorIdAsString());
264 row.put(MatchType.IN_PORT.id(), "*");
266 if (match.isPresent(MatchType.DL_SRC)) {
267 row.put(MatchType.DL_SRC.id(),
268 (HexEncode.bytesToHexString(((byte[]) flow.getMatch()
269 .getField(MatchType.DL_SRC).getValue()))));
271 row.put(MatchType.DL_SRC.id(), "*");
273 if (match.isPresent(MatchType.DL_DST)) {
274 row.put(MatchType.DL_DST.id(),
275 (HexEncode.bytesToHexString(((byte[]) flow.getMatch()
276 .getField(MatchType.DL_DST).getValue()))));
278 row.put(MatchType.DL_DST.id(), "*");
280 if (match.isPresent(MatchType.DL_TYPE)) {
281 row.put(MatchType.DL_TYPE.id(),
282 EtherTypes.getEtherTypeName(((Short) flow.getMatch()
283 .getField(MatchType.DL_TYPE).getValue())));
285 row.put(MatchType.DL_TYPE.id(), "*");
288 // Some physical switch has vlan as ffff to show "any" vlan
289 if (match.isPresent(MatchType.DL_VLAN)) {
290 if (((Short) flow.getMatch().getField(MatchType.DL_VLAN).getValue())
292 row.put(MatchType.DL_VLAN.id(), "0");
294 row.put(MatchType.DL_VLAN.id(), ((Short) flow.getMatch()
295 .getField(MatchType.DL_VLAN).getValue()).toString());
298 row.put(MatchType.DL_VLAN.id(), "*");
300 if (match.isPresent(MatchType.NW_SRC)) {
301 row.put(MatchType.NW_SRC.id(), ((InetAddress) flow.getMatch()
302 .getField(MatchType.NW_SRC).getValue()).getHostAddress());
304 row.put(MatchType.NW_SRC.id(), "*");
306 if (match.isPresent(MatchType.NW_DST)) {
307 row.put(MatchType.NW_DST.id(), ((InetAddress) flow.getMatch()
308 .getField(MatchType.NW_DST).getValue()).getHostAddress());
310 row.put(MatchType.NW_DST.id(), "*");
312 if (match.isPresent(MatchType.NW_PROTO)) {
313 row.put(MatchType.NW_PROTO.id(),
314 IPProtocols.getProtocolName(((Byte) flow.getMatch()
315 .getField(MatchType.NW_PROTO).getValue())));
317 row.put(MatchType.NW_PROTO.id(), "*");
319 if (match.isPresent(MatchType.TP_SRC)) {
320 Short tpSrc = (Short) (flow.getMatch().getField(MatchType.TP_SRC)
322 row.put(MatchType.TP_SRC.id(),
323 String.valueOf(NetUtils.getUnsignedShort(tpSrc)));
325 row.put(MatchType.TP_SRC.id(), "*");
327 if (match.isPresent(MatchType.TP_DST)) {
328 Short tpDst = (Short) (flow.getMatch().getField(MatchType.TP_DST)
330 row.put(MatchType.TP_DST.id(),
331 String.valueOf(NetUtils.getUnsignedShort(tpDst)));
333 row.put(MatchType.TP_DST.id(), "*");
336 row.put("byteCount", ((Long) flowOnNode.getByteCount()).toString());
337 row.put("packetCount", ((Long) flowOnNode.getPacketCount()).toString());
339 StringBuffer actions = new StringBuffer();
340 StringBuffer outPorts = new StringBuffer();
341 String outVlanId = null;
342 for (Action action : flow.getActions()) {
343 actions.append(action.getType().toString() + "\n");
344 if (action instanceof Output) {
345 Output ao = (Output) action;
346 if (outPorts.length() > 0) {
347 outPorts.append(" ");
349 outPorts.append(ao.getPort().getNodeConnectorIdAsString());
350 } else if (action instanceof SetVlanId) {
351 SetVlanId av = (SetVlanId) action;
352 outVlanId = String.valueOf(av.getVlanId());
355 if (outPorts.length() == 0) {
356 outPorts.append("*");
358 if (outVlanId == null) {
361 row.put("actions", actions.toString());
362 row.put("outPorts", outPorts.toString());
363 row.put("outVlanId", outVlanId);
364 row.put("durationSeconds",
365 ((Integer) flowOnNode.getDurationSeconds()).toString());
366 row.put("idleTimeout", ((Short) flow.getIdleTimeout()).toString());
367 row.put("priority", String.valueOf(flow.getPriority()));
371 private String getNodeDesc(Node node, ISwitchManager switchManager) {
372 if (switchManager == null) {
375 Description desc = (Description) switchManager.getNodeProp(node, Description.propertyName);
376 return (desc == null) ? "" : desc.getValue();