blob: fc99c49fec570890e5e190788f4cac279b0283d7 [file] [log] [blame]
Ray Milkey4f5de002014-12-17 19:26:11 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Ray Milkey4f5de002014-12-17 19:26:11 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jonathan Hart9bb32ab2015-05-05 18:17:31 -070016package org.onosproject.rest.resources;
Ray Milkey4f5de002014-12-17 19:26:11 -080017
Jian Li9d616492016-03-09 10:52:49 -080018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
Ray Milkey460f9b02016-03-29 11:56:19 -070021import com.google.common.collect.ArrayListMultimap;
22import com.google.common.collect.ListMultimap;
Ray Milkeyd43fe452015-05-29 09:35:12 -070023import org.onlab.util.ItemNotFoundException;
24import org.onosproject.net.Device;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.device.DeviceService;
27import org.onosproject.net.flow.FlowEntry;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.FlowRuleService;
30import org.onosproject.rest.AbstractWebResource;
31
Jian Li9d616492016-03-09 10:52:49 -080032import javax.ws.rs.Consumes;
33import javax.ws.rs.DELETE;
34import javax.ws.rs.GET;
35import javax.ws.rs.POST;
36import javax.ws.rs.Path;
37import javax.ws.rs.PathParam;
38import javax.ws.rs.Produces;
39import javax.ws.rs.core.Context;
40import javax.ws.rs.core.MediaType;
41import javax.ws.rs.core.Response;
42import javax.ws.rs.core.UriBuilder;
43import javax.ws.rs.core.UriInfo;
44import java.io.IOException;
45import java.io.InputStream;
Ray Milkey460f9b02016-03-29 11:56:19 -070046import java.util.ArrayList;
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -070047import java.util.List;
Jian Li9d616492016-03-09 10:52:49 -080048import java.util.stream.StreamSupport;
Ray Milkeyd43fe452015-05-29 09:35:12 -070049
Ray Milkey460f9b02016-03-29 11:56:19 -070050import static org.onlab.util.Tools.nullIsNotFound;
51
Ray Milkey4f5de002014-12-17 19:26:11 -080052/**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070053 * Query and program flow rules.
Ray Milkey4f5de002014-12-17 19:26:11 -080054 */
55
56@Path("flows")
57public class FlowsWebResource extends AbstractWebResource {
Jian Li9d616492016-03-09 10:52:49 -080058
59 @Context
Jian Licc730a62016-05-10 16:36:16 -070060 private UriInfo uriInfo;
Jian Li9d616492016-03-09 10:52:49 -080061
Jian Licc730a62016-05-10 16:36:16 -070062 private static final String DEVICE_NOT_FOUND = "Device is not found";
63 private static final String FLOW_NOT_FOUND = "Flow is not found";
64 private static final String FLOWS = "flows";
65 private static final String DEVICE_ID = "deviceId";
66 private static final String FLOW_ID = "flowId";
Ray Milkey4f5de002014-12-17 19:26:11 -080067
Jian Licc730a62016-05-10 16:36:16 -070068 private final FlowRuleService service = get(FlowRuleService.class);
69 private final ObjectNode root = mapper().createObjectNode();
70 private final ArrayNode flowsNode = root.putArray(FLOWS);
Ray Milkey4f5de002014-12-17 19:26:11 -080071
72 /**
Jian Licc730a62016-05-10 16:36:16 -070073 * Gets all flow entries. Returns array of all flow rules in the system.
74 *
75 * @return 200 OK with a collection of flows
Andrea Campanella10c4adc2015-12-03 15:27:54 -080076 * @onos.rsModel Flows
Ray Milkey4f5de002014-12-17 19:26:11 -080077 */
78 @GET
79 @Produces(MediaType.APPLICATION_JSON)
80 public Response getFlows() {
Ray Milkey4f5de002014-12-17 19:26:11 -080081 final Iterable<Device> devices = get(DeviceService.class).getDevices();
82 for (final Device device : devices) {
Phaneendra Mandaaec654c2015-09-23 19:02:23 +053083 final Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
84 if (flowEntries != null) {
85 for (final FlowEntry entry : flowEntries) {
Thomas Vachuska8683e012015-03-18 18:03:33 -070086 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
Ray Milkey4f5de002014-12-17 19:26:11 -080087 }
88 }
89 }
90
Ray Milkey3f025692015-01-26 11:15:41 -080091 return ok(root).build();
Ray Milkey4f5de002014-12-17 19:26:11 -080092 }
93
94 /**
Jian Licc730a62016-05-10 16:36:16 -070095 * Creates new flow rules. Creates and installs a new flow rules.<br>
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -070096 * Instructions description:
97 * https://wiki.onosproject.org/display/ONOS/Flow+Rule+Instructions
98 * <br>
99 * Criteria description:
100 * https://wiki.onosproject.org/display/ONOS/Flow+Rule+Criteria
101 *
Jian Licc730a62016-05-10 16:36:16 -0700102 * @param stream flow rules JSON
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700103 * @return status of the request - CREATED if the JSON is correct,
104 * BAD_REQUEST if the JSON is invalid
Jian Licc730a62016-05-10 16:36:16 -0700105 * @onos.rsModel FlowsBatchPost
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700106 */
107 @POST
108 @Consumes(MediaType.APPLICATION_JSON)
109 @Produces(MediaType.APPLICATION_JSON)
110 public Response createFlows(InputStream stream) {
111 try {
112 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
113 ArrayNode flowsArray = (ArrayNode) jsonTree.get(FLOWS);
114 List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);
115 service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
Ray Milkey460f9b02016-03-29 11:56:19 -0700116 rules.forEach(flowRule -> {
117 ObjectNode flowNode = mapper().createObjectNode();
118 flowNode.put(DEVICE_ID, flowRule.deviceId().toString())
119 .put(FLOW_ID, flowRule.id().value());
120 flowsNode.add(flowNode);
121 });
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700122 } catch (IOException ex) {
123 throw new IllegalArgumentException(ex);
124 }
Ray Milkey460f9b02016-03-29 11:56:19 -0700125 return Response.ok(root).build();
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700126 }
127
128 /**
Jian Licc730a62016-05-10 16:36:16 -0700129 * Gets flow entries of a device. Returns array of all flow rules for the
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700130 * specified device.
Jian Licc730a62016-05-10 16:36:16 -0700131 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700132 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -0700133 * @return 200 OK with a collection of flows of given device
134 * @onos.rsModel Flows
Ray Milkey4f5de002014-12-17 19:26:11 -0800135 */
136 @GET
137 @Produces(MediaType.APPLICATION_JSON)
138 @Path("{deviceId}")
139 public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530140 final Iterable<FlowEntry> flowEntries =
Ray Milkey4f5de002014-12-17 19:26:11 -0800141 service.getFlowEntries(DeviceId.deviceId(deviceId));
142
Jian Li9d616492016-03-09 10:52:49 -0800143 if (flowEntries == null || !flowEntries.iterator().hasNext()) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800144 throw new ItemNotFoundException(DEVICE_NOT_FOUND);
145 }
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530146 for (final FlowEntry entry : flowEntries) {
Thomas Vachuska8683e012015-03-18 18:03:33 -0700147 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
Ray Milkey4f5de002014-12-17 19:26:11 -0800148 }
Ray Milkey3f025692015-01-26 11:15:41 -0800149 return ok(root).build();
Ray Milkey4f5de002014-12-17 19:26:11 -0800150 }
151
152 /**
Jian Licc730a62016-05-10 16:36:16 -0700153 * Gets flow rule. Returns the flow entry specified by the device id and
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700154 * flow rule id.
Jian Licc730a62016-05-10 16:36:16 -0700155 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700156 * @param deviceId device identifier
157 * @param flowId flow rule identifier
Jian Licc730a62016-05-10 16:36:16 -0700158 * @return 200 OK with a flows of given device and flow
159 * @onos.rsModel Flows
Ray Milkey4f5de002014-12-17 19:26:11 -0800160 */
161 @GET
162 @Produces(MediaType.APPLICATION_JSON)
163 @Path("{deviceId}/{flowId}")
164 public Response getFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
165 @PathParam("flowId") long flowId) {
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530166 final Iterable<FlowEntry> flowEntries =
Ray Milkey4f5de002014-12-17 19:26:11 -0800167 service.getFlowEntries(DeviceId.deviceId(deviceId));
168
Jian Li9d616492016-03-09 10:52:49 -0800169 if (flowEntries == null || !flowEntries.iterator().hasNext()) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800170 throw new ItemNotFoundException(DEVICE_NOT_FOUND);
171 }
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530172 for (final FlowEntry entry : flowEntries) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800173 if (entry.id().value() == flowId) {
Thomas Vachuska8683e012015-03-18 18:03:33 -0700174 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
Ray Milkey4f5de002014-12-17 19:26:11 -0800175 }
176 }
Ray Milkey3f025692015-01-26 11:15:41 -0800177 return ok(root).build();
Ray Milkey4f5de002014-12-17 19:26:11 -0800178 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700179
180 /**
Jian Licc730a62016-05-10 16:36:16 -0700181 * Creates new flow rule. Creates and installs a new flow rule for the
Andrea Campanella881f29f2016-03-03 19:18:42 -0800182 * specified device. <br>
183 * Instructions description:
184 * https://wiki.onosproject.org/display/ONOS/Flow+Rule+Instructions
185 * <br>
186 * Criteria description:
187 * https://wiki.onosproject.org/display/ONOS/Flow+Rule+Criteria
188 *
Madan Jampani0dbac7a2015-06-25 10:37:45 -0700189 * @param deviceId device identifier
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700190 * @param stream flow rule JSON
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700191 * @return status of the request - CREATED if the JSON is correct,
Ray Milkeyd43fe452015-05-29 09:35:12 -0700192 * BAD_REQUEST if the JSON is invalid
Jian Licc730a62016-05-10 16:36:16 -0700193 * @onos.rsModel FlowsPost
Ray Milkeyd43fe452015-05-29 09:35:12 -0700194 */
195 @POST
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700196 @Path("{deviceId}")
Ray Milkeyd43fe452015-05-29 09:35:12 -0700197 @Consumes(MediaType.APPLICATION_JSON)
198 @Produces(MediaType.APPLICATION_JSON)
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700199 public Response createFlow(@PathParam("deviceId") String deviceId,
200 InputStream stream) {
Ray Milkeyd43fe452015-05-29 09:35:12 -0700201 try {
Ray Milkey5d915f42015-08-13 10:27:53 -0700202 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
203 JsonNode specifiedDeviceId = jsonTree.get("deviceId");
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700204 if (specifiedDeviceId != null &&
205 !specifiedDeviceId.asText().equals(deviceId)) {
206 throw new IllegalArgumentException(
207 "Invalid deviceId in flow creation request");
208 }
Ray Milkey5d915f42015-08-13 10:27:53 -0700209 jsonTree.put("deviceId", deviceId);
210 FlowRule rule = codec(FlowRule.class).decode(jsonTree, this);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700211 service.applyFlowRules(rule);
Jian Li9d616492016-03-09 10:52:49 -0800212 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
213 .path("flows")
214 .path(deviceId)
Ray Milkey90289b02016-03-31 15:23:28 -0700215 .path(Long.toString(rule.id().value()));
Jian Li9d616492016-03-09 10:52:49 -0800216
217 return Response
218 .created(locationBuilder.build())
219 .build();
220 } catch (IOException ex) {
Ray Milkey5d915f42015-08-13 10:27:53 -0700221 throw new IllegalArgumentException(ex);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700222 }
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700223 }
224
225 /**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700226 * Remove flow rule. Removes the specified flow rule.
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700227 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700228 * @param deviceId device identifier
229 * @param flowId flow rule identifier
Jian Lic2a542b2016-05-10 11:48:19 -0700230 * @return 204 NO CONTENT
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700231 */
232 @DELETE
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700233 @Path("{deviceId}/{flowId}")
Jian Lic2a542b2016-05-10 11:48:19 -0700234 public Response deleteFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
Jian Licc730a62016-05-10 16:36:16 -0700235 @PathParam("flowId") long flowId) {
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530236 final Iterable<FlowEntry> flowEntries =
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700237 service.getFlowEntries(DeviceId.deviceId(deviceId));
238
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530239 if (!flowEntries.iterator().hasNext()) {
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700240 throw new ItemNotFoundException(DEVICE_NOT_FOUND);
241 }
242
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530243 StreamSupport.stream(flowEntries.spliterator(), false)
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700244 .filter(entry -> entry.id().value() == flowId)
245 .forEach(service::removeFlowRules);
Jian Lic2a542b2016-05-10 11:48:19 -0700246 return Response.noContent().build();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700247 }
248
Ray Milkey460f9b02016-03-29 11:56:19 -0700249 /**
250 * Removes a batch of flow rules.
Ray Milkeybee35092016-04-12 10:01:26 -0700251 *
252 * @param stream stream for posted JSON
Jian Licc730a62016-05-10 16:36:16 -0700253 * @return 204 NO CONTENT
Ray Milkey460f9b02016-03-29 11:56:19 -0700254 */
255 @DELETE
Jian Lic2a542b2016-05-10 11:48:19 -0700256 public Response deleteFlows(InputStream stream) {
Ray Milkey460f9b02016-03-29 11:56:19 -0700257 ListMultimap<DeviceId, Long> deviceMap = ArrayListMultimap.create();
258 List<FlowEntry> rulesToRemove = new ArrayList<>();
259
260 try {
261 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
262
263 JsonNode jsonFlows = jsonTree.get("flows");
264
265 jsonFlows.forEach(node -> {
266 DeviceId deviceId =
267 DeviceId.deviceId(
268 nullIsNotFound(node.get(DEVICE_ID),
Jian Licc730a62016-05-10 16:36:16 -0700269 DEVICE_NOT_FOUND).asText());
Ray Milkey460f9b02016-03-29 11:56:19 -0700270 long flowId = nullIsNotFound(node.get(FLOW_ID),
Jian Licc730a62016-05-10 16:36:16 -0700271 FLOW_NOT_FOUND).asLong();
Ray Milkey460f9b02016-03-29 11:56:19 -0700272 deviceMap.put(deviceId, flowId);
273
274 });
275 } catch (IOException ex) {
276 throw new IllegalArgumentException(ex);
277 }
278
279 deviceMap.keySet().forEach(deviceId -> {
280 List<Long> flowIds = deviceMap.get(deviceId);
281 Iterable<FlowEntry> entries = service.getFlowEntries(deviceId);
282 flowIds.forEach(flowId -> {
283 StreamSupport.stream(entries.spliterator(), false)
284 .filter(entry -> flowId == entry.id().value())
285 .forEach(rulesToRemove::add);
286 });
287 });
288
289 service.removeFlowRules(rulesToRemove.toArray(new FlowEntry[0]));
Jian Lic2a542b2016-05-10 11:48:19 -0700290 return Response.noContent().build();
Ray Milkey460f9b02016-03-29 11:56:19 -0700291 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800292}