Fix Enqueue Action in Flow UI
[controller.git] / opendaylight / web / flows / src / main / java / org / opendaylight / controller / flows / web / Flows.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.flows.web;
10
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.TreeMap;
18
19 import javax.servlet.http.HttpServletRequest;
20
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;
47
48 import com.google.gson.Gson;
49
50 @Controller
51 @RequestMapping("/")
52 public class Flows implements IDaylightWeb {
53     private static final UserLevel AUTH_LEVEL = UserLevel.CONTAINERUSER;
54     private static final String WEB_NAME = "Flows";
55
56     private static final String WEB_ID = "flows";
57     private static final short WEB_ORDER = 2;
58
59     private final Gson gson;
60
61     public Flows() {
62         ServiceHelper.registerGlobalService(IDaylightWeb.class, this, null);
63         gson = new Gson();
64     }
65
66     @Override
67     public String getWebName() {
68         return WEB_NAME;
69     }
70
71     @Override
72     public String getWebId() {
73         return WEB_ID;
74     }
75
76     @Override
77     public short getWebOrder() {
78         return WEB_ORDER;
79     }
80
81     @Override
82     public boolean isAuthorized(UserLevel userLevel) {
83         return userLevel.ordinal() <= AUTH_LEVEL.ordinal();
84     }
85
86     @RequestMapping(value = "/main")
87     @ResponseBody
88     public Map<String, Object> getFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
89         String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
90
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) {
95             return null;
96         }
97
98         // fetch frm
99         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
100                 IForwardingRulesManager.class, containerName, this);
101         if (frm == null) {
102             return null;
103         }
104
105         // fetch sm
106         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
107                 this);
108         if (switchManager == null) {
109             return null;
110         }
111
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());
122             flowSet.add(entry);
123         }
124
125         Map<String, Object> output = new HashMap<String, Object>(2);
126         output.put("flows", flowSet);
127         output.put("privilege", privilege);
128         return output;
129     }
130
131     @RequestMapping(value = "/node-ports")
132     @ResponseBody
133     public Map<String, Object> getNodePorts(HttpServletRequest request, @RequestParam(required = false) String container) {
134         String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
135
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) {
139             return null;
140         }
141
142         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
143                 this);
144         if (switchManager == null) {
145             return null;
146         }
147
148         Map<String, Object> nodes = new HashMap<String, Object>();
149         Map<String, String> port;
150
151         for (Switch node : switchManager.getNetworkDevices()) {
152             port = new HashMap<String, String>(); // new port
153             Set<NodeConnector> nodeConnectorSet = node.getNodeConnectors();
154
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() + ")");
161                 }
162             }
163
164             // add ports
165             Map<String, Object> entry = new HashMap<String, Object>();
166             entry.put("ports", port);
167
168             // add name
169             entry.put("name", getNodeDesc(node.getNode(), switchManager));
170
171             // add to the node
172             nodes.put(node.getNode().toString(), entry);
173         }
174
175         return nodes;
176     }
177
178     @RequestMapping(value = "/node-flows")
179     @ResponseBody
180     public Map<String, Object> getNodeFlows(HttpServletRequest request, @RequestParam(required = false) String container) {
181         String containerName = (container == null) ? GlobalConstants.DEFAULT.toString() : container;
182
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) {
186             return null;
187         }
188
189         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName,
190                 this);
191         if (switchManager == null) {
192             return null;
193         }
194         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
195                 IForwardingRulesManager.class, containerName, this);
196         if (frm == null) {
197             return null;
198         }
199
200         Map<String, Object> nodes = new HashMap<String, Object>();
201
202         for (Switch sw : switchManager.getNetworkDevices()) {
203             Node node = sw.getNode();
204
205             List<FlowConfig> flows = frm.getStaticFlows(node);
206
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();
211             }
212
213             nodes.put(nodeDesc, flows.size());
214         }
215
216         return nodes;
217     }
218
219     @RequestMapping(value = "/flow", method = RequestMethod.POST)
220     @ResponseBody
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;
225
226         // Authorization check
227         String userName = request.getUserPrincipal().getName();
228         if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
229             return "Operation not authorized";
230         }
231
232         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
233                 IForwardingRulesManager.class, containerName, this);
234         if (frm == null) {
235             return null;
236         }
237
238         FlowConfig flow = gson.fromJson(body, FlowConfig.class);
239
240         Node node = Node.fromString(nodeId);
241         flow.setNode(node);
242
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);
249             }
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);
255             }
256         }
257
258         return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result.getDescription();
259     }
260
261     @RequestMapping(value = "/flow/{nodeId}/{name:.*}", method = RequestMethod.POST)
262     @ResponseBody
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;
267
268         // Authorization check
269         String userName = request.getUserPrincipal().getName();
270         if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
271             return "Operation not authorized";
272         }
273
274         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
275                 IForwardingRulesManager.class, containerName, this);
276         if (frm == null) {
277             return null;
278         }
279
280         Status result = null;
281         Node node = Node.fromString(nodeId);
282         if (node == null) {
283             return null;
284         }
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);
290             }
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);
296             }
297         } else {
298             result = new Status(StatusCode.BADREQUEST, "Unknown action");
299         }
300
301         return (result.isSuccess()) ? StatusCode.SUCCESS.toString() : result.getDescription();
302     }
303
304     @SuppressWarnings("unchecked")
305     @RequestMapping(value = "/flow/deleteFlows", method = RequestMethod.POST)
306     @ResponseBody
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;
310
311         // Authorization check
312         String userName = request.getUserPrincipal().getName();
313         if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
314             return "Operation not authorized";
315         }
316         IForwardingRulesManager frm = (IForwardingRulesManager) ServiceHelper.getInstance(
317                 IForwardingRulesManager.class, containerName, this);
318         if (frm == null) {
319             return "Forwarding Rules Manager is not available";
320         }
321
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");
325         String status = "";
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);
332             } else {
333                 status = flowEntry.get("name") + ", " + status;
334             }
335         }
336         if (!status.equals("")) {
337             return "Could not remove " + status.substring(0, status.length() - 2) + " Flow(s)";
338         } else {
339             return "Success";
340         }
341     }
342
343     @RequestMapping(value = "/valid-flows/{nodeId}")
344     @ResponseBody
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;
348
349         // Authorization check
350         String userName = request.getUserPrincipal().getName();
351         if (DaylightWebUtil.getContainerPrivilege(userName, containerName, this) != Privilege.WRITE) {
352             return "Operation not authorized";
353         }
354
355         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
356         if (switchManager == null) {
357             return null;
358         }
359
360         Map<String, String> result = new TreeMap<String, String>();
361
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");
410             }
411         }
412
413         return result;
414     }
415
416     private boolean actionCompare(String name, ActionType type) {
417         return name.equals(type.getId().toLowerCase());
418     }
419
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;
424     }
425
426 }