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.Node;
28 import org.opendaylight.controller.sal.core.NodeConnector;
29 import org.opendaylight.controller.sal.core.TimeStamp;
30 import org.opendaylight.controller.sal.flowprogrammer.Flow;
31 import org.opendaylight.controller.sal.match.Match;
32 import org.opendaylight.controller.sal.match.MatchType;
33 import org.opendaylight.controller.sal.reader.FlowOnNode;
34 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
35 import org.opendaylight.controller.sal.utils.EtherTypes;
36 import org.opendaylight.controller.sal.utils.GlobalConstants;
37 import org.opendaylight.controller.sal.utils.HexEncode;
38 import org.opendaylight.controller.sal.utils.IPProtocols;
39 import org.opendaylight.controller.sal.utils.NetUtils;
40 import org.opendaylight.controller.sal.utils.ServiceHelper;
41 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
42 import org.opendaylight.controller.switchmanager.ISwitchManager;
43 import org.opendaylight.controller.web.DaylightWebUtil;
44 import org.opendaylight.controller.web.IDaylightWeb;
45 import org.springframework.stereotype.Controller;
46 import org.springframework.web.bind.annotation.RequestMapping;
47 import org.springframework.web.bind.annotation.RequestMethod;
48 import org.springframework.web.bind.annotation.RequestParam;
49 import org.springframework.web.bind.annotation.ResponseBody;
53 public class Troubleshoot implements IDaylightWeb {
54 private static final UserLevel AUTH_LEVEL = UserLevel.CONTAINERUSER;
55 private static final List<String> flowStatsColumnNames = Arrays.asList("Node", "In Port",
56 "DL Src", "DL Dst", "DL Type", "DL Vlan", "NW Src", "NW Dst",
57 "NW Proto", "TP Src", "TP Dst", "Actions", "Bytes", "Packets",
58 "Time (s)", "Timeout (s)", "Out Port(s)", "Out Vlan",
60 private static final List<String> portStatsColumnNames = Arrays.asList("Node Connector",
61 "Rx Pkts", "Tx Pkts", "Rx Bytes", "Tx Bytes", "Rx Drops",
62 "Tx Drops", "Rx Errs", "Tx Errs", "Rx Frame Errs",
63 "Rx OverRun Errs", "Rx CRC Errs", "Collisions");
64 private static final List<String> nodesColumnNames = Arrays.asList("Node", "Node ID", "Statistics");
65 private static final List<String> nodeStatsColumnNames = Arrays.asList("Node", "Node ID", "Statistics");
66 private final String WEB_NAME = "Troubleshoot";
67 private final String WEB_ID = "troubleshoot";
68 private final short WEB_ORDER = 4;
71 public Troubleshoot() {
72 ServiceHelper.registerGlobalService(IDaylightWeb.class, this, null);
76 public String getWebName() {
81 public String getWebId() {
86 public short getWebOrder() {
91 public boolean isAuthorized(UserLevel userLevel) {
92 return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
95 @RequestMapping(value = "/existingNodes", method = RequestMethod.GET)
97 public TroubleshootingJsonBean getExistingNodes(HttpServletRequest request, @RequestParam(required = false) String container) {
98 List<Map<String, String>> lines = new ArrayList<Map<String, String>>();
99 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
101 // Derive the privilege this user has on the current container
102 String userName = request.getUserPrincipal().getName();
103 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
105 if (privilege != Privilege.NONE) {
106 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
107 .getInstance(ISwitchManager.class, containerName, this);
108 Set<Node> nodeSet = (switchManager != null) ? switchManager.getNodes() : null;
109 if (nodeSet != null) {
110 for (Node node : nodeSet) {
111 Map<String, String> device = new HashMap<String, String>();
112 device.put("nodeName", switchManager.getNodeDescription(node));
113 device.put("nodeId", node.toString());
119 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
120 result.setColumnNames(nodesColumnNames);
121 result.setNodeData(lines);
125 @RequestMapping(value = "/uptime", method = RequestMethod.GET)
127 public TroubleshootingJsonBean getUptime(HttpServletRequest request, @RequestParam(required = false) String container) {
128 List<Map<String, String>> lines = new ArrayList<Map<String, String>>();
129 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
131 // Derive the privilege this user has on the current container
132 String userName = request.getUserPrincipal().getName();
133 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
135 if (privilege != Privilege.NONE) {
136 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
137 .getInstance(ISwitchManager.class, containerName, this);
138 Set<Node> nodeSet = (switchManager != null) ? switchManager.getNodes() : null;
139 if (nodeSet != null) {
140 for (Node node : nodeSet) {
141 Map<String, String> device = new HashMap<String, String>();
142 device.put("nodeName", switchManager.getNodeDescription(node));
143 device.put("nodeId", node.toString());
144 TimeStamp timeStamp = (TimeStamp) switchManager.getNodeProp(
145 node, TimeStamp.TimeStampPropName);
146 Long time = (timeStamp == null) ? 0 : timeStamp.getValue();
147 String date = (time == 0) ? "" : (new Date(time)).toString();
148 device.put("connectedSince", date);
154 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
155 result.setColumnNames(nodeStatsColumnNames);
156 result.setNodeData(lines);
160 @RequestMapping(value = "/flowStats", method = RequestMethod.GET)
162 public TroubleshootingJsonBean getFlowStats(
163 @RequestParam("nodeId") String nodeId,
164 HttpServletRequest request, @RequestParam(required = false) String container) {
165 List<Map<String, String>> cells = new ArrayList<Map<String, String>>();
166 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
168 // Derive the privilege this user has on the current container
169 String userName = request.getUserPrincipal().getName();
170 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
172 if (privilege != Privilege.NONE) {
173 IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
174 .getInstance(IStatisticsManager.class, containerName, this);
175 if (statisticsManager != null) {
176 Node node = Node.fromString(nodeId);
177 List<FlowOnNode> statistics = statisticsManager.getFlows(node);
178 for (FlowOnNode stats : statistics) {
179 cells.add(this.convertFlowStatistics(node, stats, containerName));
184 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
185 result.setColumnNames(flowStatsColumnNames);
186 result.setNodeData(cells);
190 @RequestMapping(value = "/portStats", method = RequestMethod.GET)
192 public TroubleshootingJsonBean getPortStats(
193 @RequestParam("nodeId") String nodeId,
194 HttpServletRequest request, @RequestParam(required = false) String container) {
195 List<Map<String, String>> cells = new ArrayList<Map<String, String>>();
196 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
198 // Derive the privilege this user has on the current container
199 String userName = request.getUserPrincipal().getName();
200 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
202 if (privilege != Privilege.NONE) {
203 IStatisticsManager statisticsManager = (IStatisticsManager) ServiceHelper
204 .getInstance(IStatisticsManager.class, containerName, this);
205 if (statisticsManager != null) {
206 Node node = Node.fromString(nodeId);
207 List<NodeConnectorStatistics> statistics = statisticsManager
208 .getNodeConnectorStatistics(node);
209 for (NodeConnectorStatistics stats : statistics) {
210 cells.add(this.convertPortsStatistics(stats));
215 TroubleshootingJsonBean result = new TroubleshootingJsonBean();
216 result.setColumnNames(portStatsColumnNames);
217 result.setNodeData(cells);
221 private Map<String, String> convertPortsStatistics(
222 NodeConnectorStatistics ncStats) {
223 Map<String, String> row = new HashMap<String, String>();
225 row.put("nodeConnector",
226 String.valueOf(ncStats.getNodeConnector().toString()));
227 row.put("rxPkts", String.valueOf(ncStats.getReceivePacketCount()));
228 row.put("txPkts", String.valueOf(ncStats.getTransmitPacketCount()));
229 row.put("rxBytes", String.valueOf(ncStats.getReceiveByteCount()));
230 row.put("txBytes", String.valueOf(ncStats.getTransmitByteCount()));
231 row.put("rxDrops", String.valueOf(ncStats.getReceiveDropCount()));
232 row.put("txDrops", String.valueOf(ncStats.getTransmitDropCount()));
233 row.put("rxErrors", String.valueOf(ncStats.getReceiveErrorCount()));
234 row.put("txErrors", String.valueOf(ncStats.getTransmitErrorCount()));
235 row.put("rxFrameErrors",
236 String.valueOf(ncStats.getReceiveFrameErrorCount()));
237 row.put("rxOverRunErrors",
238 String.valueOf(ncStats.getReceiveOverRunErrorCount()));
239 row.put("rxCRCErrors",
240 String.valueOf(ncStats.getReceiveCRCErrorCount()));
241 row.put("collisions", String.valueOf(ncStats.getCollisionCount()));
246 private Map<String, String> convertFlowStatistics(Node node,
247 FlowOnNode flowOnNode,
248 String containerName) {
249 Map<String, String> row = new HashMap<String, String>();
250 Flow flow = flowOnNode.getFlow();
251 Match match = flow.getMatch();
252 ISwitchManager switchManager = (ISwitchManager) ServiceHelper
253 .getInstance(ISwitchManager.class, containerName, this);
254 String desc = (switchManager == null)?
255 "" : switchManager.getNodeDescription(node);
256 desc = (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()));