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.flows.web;
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
17 import java.util.TreeMap;
19 import javax.servlet.http.HttpServletRequest;
21 import org.opendaylight.controller.forwardingrulesmanager.FlowConfig;
22 import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManager;
23 import org.opendaylight.controller.sal.action.Action;
24 import org.opendaylight.controller.sal.action.ActionType;
25 import org.opendaylight.controller.sal.action.SupportedFlowActions;
26 import org.opendaylight.controller.sal.authorization.Privilege;
27 import org.opendaylight.controller.sal.authorization.UserLevel;
28 import org.opendaylight.controller.sal.core.Description;
29 import org.opendaylight.controller.sal.core.Name;
30 import org.opendaylight.controller.sal.core.Node;
31 import org.opendaylight.controller.sal.core.NodeConnector;
32 import org.opendaylight.controller.sal.utils.GlobalConstants;
33 import org.opendaylight.controller.sal.utils.ServiceHelper;
34 import org.opendaylight.controller.sal.utils.Status;
35 import org.opendaylight.controller.sal.utils.StatusCode;
36 import org.opendaylight.controller.switchmanager.ISwitchManager;
37 import org.opendaylight.controller.switchmanager.Switch;
38 import org.opendaylight.controller.switchmanager.SwitchConfig;
39 import org.opendaylight.controller.web.DaylightWebUtil;
40 import org.opendaylight.controller.web.IDaylightWeb;
41 import org.springframework.stereotype.Controller;
42 import org.springframework.web.bind.annotation.PathVariable;
43 import org.springframework.web.bind.annotation.RequestMapping;
44 import org.springframework.web.bind.annotation.RequestMethod;
45 import org.springframework.web.bind.annotation.RequestParam;
46 import org.springframework.web.bind.annotation.ResponseBody;
48 import com.google.gson.Gson;
52 public class Flows implements IDaylightWeb {
53 private static final UserLevel AUTH_LEVEL = UserLevel.CONTAINERUSER;
54 private static final String WEB_NAME = "Flows";
56 private static final String WEB_ID = "flows";
57 private static final short WEB_ORDER = 2;
59 private final Gson gson;
62 ServiceHelper.registerGlobalService(IDaylightWeb.class, this, null);
67 public String getWebName() {
72 public String getWebId() {
77 public short getWebOrder() {
82 public boolean isAuthorized(UserLevel userLevel) {
83 return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
86 @RequestMapping(value = "/main")
88 public Map<String, Object> getFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
89 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
91 // Derive the privilege this user has on the current container
92 String userName = request.getUserPrincipal().getName();
93 Privilege privilege = DaylightWebUtil.getContainerPrivilege(userName, containerName, this);
94 if (privilege == Privilege.NONE) {
99 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
100 IForwardingRulesManager.class, containerName, this);
106 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
108 if (switchManager == null) {
112 // get static flow list
113 List<FlowConfig> staticFlowList = frm.getStaticFlows();
114 Set<Map<String, Object>> flowSet = new HashSet<Map<String, Object>>();
115 for (FlowConfig flowConfig : staticFlowList) {
116 Map<String, Object> entry = new HashMap<String, Object>();
117 entry.put("flow", flowConfig);
118 entry.put("name", flowConfig.getName());
119 Node node = flowConfig.getNode();
120 entry.put("node", getNodeDesc(node, switchManager));
121 entry.put("nodeId", node.toString());
125 Map<String, Object> output = new HashMap<String, Object>(2);
126 output.put("flows", flowSet);
127 output.put("privilege", privilege);
131 @RequestMapping(value = "/node-ports")
133 public Map<String, Object> getNodePorts(HttpServletRequest request, @RequestParam(required = false) String container) {
134 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
136 // Derive the privilege this user has on the current container
137 String userName = request.getUserPrincipal().getName();
138 if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
142 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
144 if (switchManager == null) {
148 Map<String, Object> nodes = new HashMap<String, Object>();
149 Map<String, String> port;
151 for (Switch node : switchManager.getNetworkDevices()) {
152 port = new HashMap<String, String>(); // new port
153 Set<NodeConnector> nodeConnectorSet = node.getNodeConnectors();
155 if (nodeConnectorSet != null) {
156 for (NodeConnector nodeConnector : nodeConnectorSet) {
157 String nodeConnectorName = ((Name) switchManager.getNodeConnectorProp(nodeConnector,
158 Name.NamePropName)).getValue();
159 port.put( nodeConnector.getID().toString(),
160 nodeConnectorName + "(" + nodeConnector.getNodeConnectorIDString() + ")");
165 Map<String, Object> entry = new HashMap<String, Object>();
166 entry.put("ports", port);
169 entry.put("name", getNodeDesc(node.getNode(), switchManager));
172 nodes.put(node.getNode().toString(), entry);
178 @RequestMapping(value = "/node-flows")
180 public Map<String, Object> getNodeFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
181 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
183 // Derive the privilege this user has on the current container
184 String userName = request.getUserPrincipal().getName();
185 if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) == Privilege.NONE) {
189 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
191 if (switchManager == null) {
194 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
195 IForwardingRulesManager.class, containerName, this);
200 Map<String, Object> nodes = new HashMap<String, Object>();
202 for (Switch sw : switchManager.getNetworkDevices()) {
203 Node node = sw.getNode();
205 List<FlowConfig> flows = frm.getStaticFlows(node);
207 String nodeDesc = node.toString();
208 SwitchConfig config = switchManager.getSwitchConfig(node.toString());
209 if ((config != null) && (config.getProperty(Description.propertyName) != null)) {
210 nodeDesc = ((Description) config.getProperty(Description.propertyName)).getValue();
213 nodes.put(nodeDesc, flows.size());
219 @RequestMapping(value = "/flow", method = RequestMethod.POST)
221 public String actionFlow(@RequestParam(required = true) String action, @RequestParam(required = false) String body,
222 @RequestParam(required = true) String nodeId, HttpServletRequest request,
223 @RequestParam(required = false) String container) {
224 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
226 // Authorization check
227 String userName = request.getUserPrincipal().getName();
228 if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
229 return "Operation not authorized";
232 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
233 IForwardingRulesManager.class, containerName, this);
238 FlowConfig flow = gson.fromJson(body, FlowConfig.class);
240 Node node = Node.fromString(nodeId);
243 Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
244 if (action.equals("add")) {
245 result = frm.addStaticFlow(flow);
246 if (result.isSuccess()) {
247 DaylightWebUtil.auditlog("Flow Entry", userName, "added", flow.getName() + " on Node "
248 + DaylightWebUtil.getNodeDesc(node, containerName, this), containerName);
250 } else if (action.equals("edit")){
251 result = frm.modifyStaticFlow(flow);
252 if (result.isSuccess()) {
253 DaylightWebUtil.auditlog("Flow Entry", userName, "updated", flow.getName() + " on Node "
254 + DaylightWebUtil.getNodeDesc(node, containerName, this), containerName);
258 return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result.getDescription();
261 @RequestMapping(value = "/flow/{nodeId}/{name:.*}", method = RequestMethod.POST)
263 public String removeFlow(@PathVariable("nodeId") String nodeId, @PathVariable("name") String name,
264 @RequestParam(required = true) String action, HttpServletRequest request,
265 @RequestParam(required = false) String container) {
266 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
268 // Authorization check
269 String userName = request.getUserPrincipal().getName();
270 if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
271 return "Operation not authorized";
274 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
275 IForwardingRulesManager.class, containerName, this);
280 Status result = null;
281 Node node = Node.fromString(nodeId);
285 if (action.equals("remove")) {
286 result = frm.removeStaticFlow(name, node);
287 if (result.isSuccess()) {
288 DaylightWebUtil.auditlog("Flow Entry", userName, "removed",
289 name + " on Node " + DaylightWebUtil.getNodeDesc(node, containerName, this), containerName);
291 } else if (action.equals("toggle")) {
292 result = frm.toggleStaticFlowStatus(name, node);
293 if (result.isSuccess()) {
294 DaylightWebUtil.auditlog("Flow Entry", userName, "toggled",
295 name + " on Node " + DaylightWebUtil.getNodeDesc(node, containerName, this), containerName);
298 result = new Status(StatusCode.BADREQUEST, "Unknown action");
301 return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result.getDescription();
304 @SuppressWarnings("unchecked")
305 @RequestMapping(value = "/flow/deleteFlows", method = RequestMethod.POST)
307 public String removeSelectedFlows(@RequestParam(required = false) String body, HttpServletRequest request,
308 @RequestParam(required = false) String container) {
309 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
311 // Authorization check
312 String userName = request.getUserPrincipal().getName();
313 if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
314 return "Operation not authorized";
316 IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
317 IForwardingRulesManager.class, containerName, this);
319 return "Forwarding Rules Manager is not available";
322 List<Map<String, String>> flowList = new ArrayList<Map<String, String>>();
323 flowList = gson.fromJson(body, flowList.getClass());
324 Status result = new Status(StatusCode.BADREQUEST, "Invalid request");
326 for (Map<String, String> flowEntry : flowList) {
327 Node node = Node.fromString(flowEntry.get("node"));
328 result = frm.removeStaticFlow(flowEntry.get("name"), node);
329 if (result.isSuccess()) {
330 DaylightWebUtil.auditlog("Flow Entry", userName, "removed", flowEntry.get("name") + " on Node "
331 + DaylightWebUtil.getNodeDesc(node, containerName, this), containerName);
333 status = flowEntry.get("name") + ", " + status;
336 if (!status.equals("")) {
337 return "Could not remove " + status.substring(0, status.length() - 2) + " Flow(s)";
343 @RequestMapping(value = "/valid-flows/{nodeId}")
345 public Object getValidActions(HttpServletRequest request, @RequestParam(required = false) String container,
346 @PathVariable("nodeId") String nodeId) {
347 String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
349 // Authorization check
350 String userName = request.getUserPrincipal().getName();
351 if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
352 return "Operation not authorized";
355 ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
356 if (switchManager == null) {
360 Map<String, String> result = new TreeMap<String, String>();
362 Node node = Node.fromString(nodeId);
363 SupportedFlowActions supportedFlows = (SupportedFlowActions) switchManager.getNodeProp(node, "supportedFlowActions");
364 List<Class<? extends Action>> actions = supportedFlows.getActions();
365 for (Class<? extends Action> action : actions) {
366 if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Drop.class)) {
367 result.put(ActionType.DROP.toString(), "Drop");
368 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Loopback.class)) {
369 result.put(ActionType.LOOPBACK.toString(), "Loopback");
370 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Flood.class)) {
371 result.put(ActionType.FLOOD.toString(), "Flood");
372 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.FloodAll.class)) {
373 result.put(ActionType.FLOOD_ALL.toString(), "Flood All");
374 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Controller.class)) {
375 result.put(ActionType.CONTROLLER.toString(), "Controller");
376 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SwPath.class)) {
377 result.put(ActionType.SW_PATH.toString(), "Software Path");
378 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.HwPath.class)) {
379 result.put(ActionType.HW_PATH.toString(), "Hardware Path");
380 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Output.class)) {
381 result.put(ActionType.OUTPUT.toString(), "Output");
382 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.Enqueue.class)) {
383 result.put(ActionType.ENQUEUE.toString(), "Enqueue");
384 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetDlSrc.class)) {
385 result.put(ActionType.SET_DL_SRC.toString(), "Set Datalayer Source Address");
386 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetDlDst.class)) {
387 result.put(ActionType.SET_DL_DST.toString(), "Set Datalayer Destination Address");
388 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetVlanId.class)) {
389 result.put(ActionType.SET_VLAN_ID.toString(), "Set VLAN ID");
390 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetVlanPcp.class)) {
391 result.put(ActionType.SET_VLAN_PCP.toString(), "Set VLAN Priority");
392 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetVlanCfi.class)) {
393 result.put(ActionType.SET_VLAN_CFI.toString(), "Set VLAN CFI");
394 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.PopVlan.class)) {
395 result.put(ActionType.POP_VLAN.toString(), "Pop VLAN");
396 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.PushVlan.class)) {
397 result.put(ActionType.PUSH_VLAN.toString(), "Push VLAN");
398 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetDlType.class)) {
399 result.put(ActionType.SET_DL_TYPE.toString(), "Set EtherType");
400 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetNwSrc.class)) {
401 result.put(ActionType.SET_NW_SRC.toString(), "Set Network Source Address");
402 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetNwDst.class)) {
403 result.put(ActionType.SET_NW_DST.toString(), "Set Network Destination Address");
404 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetNwTos.class)) {
405 result.put(ActionType.SET_NW_TOS.toString(), "Modify ToS Bits");
406 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetTpSrc.class)) {
407 result.put(ActionType.SET_TP_SRC.toString(), "Modify Transport Source Port");
408 } else if (action.isAssignableFrom(org.opendaylight.controller.sal.action.SetTpDst.class)) {
409 result.put(ActionType.SET_TP_DST.toString(), "Modify Transport Destination Port");
416 private boolean actionCompare(String name, ActionType type) {
417 return name.equals(type.getId().toLowerCase());
420 private String getNodeDesc(Node node, ISwitchManager switchManager) {
421 Description desc = (Description) switchManager.getNodeProp(node, Description.propertyName);
422 String description = (desc == null) ? "" : desc.getValue();
423 return (description.isEmpty() || description.equalsIgnoreCase("none")) ? node.toString() : description;