blob: 2f532ac4678f8dba5834d428043ea2e52db7fdc3 [file] [log] [blame]
Ray Milkey4f5de002014-12-17 19:26:11 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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;
Jian Li2907ad22016-05-12 23:08:54 -070024import org.onosproject.app.ApplicationService;
25import org.onosproject.core.ApplicationId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070026import org.onosproject.net.Device;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.device.DeviceService;
29import org.onosproject.net.flow.FlowEntry;
30import org.onosproject.net.flow.FlowRule;
31import org.onosproject.net.flow.FlowRuleService;
rsahot0362c2c6cc2018-06-22 14:35:07 -040032import org.onosproject.net.flow.IndexTableId;
Ray Milkeyd43fe452015-05-29 09:35:12 -070033import org.onosproject.rest.AbstractWebResource;
34
Jian Li9d616492016-03-09 10:52:49 -080035import javax.ws.rs.Consumes;
36import javax.ws.rs.DELETE;
37import javax.ws.rs.GET;
38import javax.ws.rs.POST;
39import javax.ws.rs.Path;
40import javax.ws.rs.PathParam;
41import javax.ws.rs.Produces;
Jian Li2907ad22016-05-12 23:08:54 -070042import javax.ws.rs.QueryParam;
Jian Li9d616492016-03-09 10:52:49 -080043import javax.ws.rs.core.Context;
44import javax.ws.rs.core.MediaType;
45import javax.ws.rs.core.Response;
46import javax.ws.rs.core.UriBuilder;
47import javax.ws.rs.core.UriInfo;
48import java.io.IOException;
49import java.io.InputStream;
Ray Milkey460f9b02016-03-29 11:56:19 -070050import java.util.ArrayList;
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -070051import java.util.List;
Jian Li9d616492016-03-09 10:52:49 -080052import java.util.stream.StreamSupport;
Ray Milkeyd43fe452015-05-29 09:35:12 -070053
Ray Milkey131c0682016-10-18 11:12:50 -070054import static org.onlab.util.Tools.nullIsIllegal;
Ray Milkey460f9b02016-03-29 11:56:19 -070055import static org.onlab.util.Tools.nullIsNotFound;
Ray Milkey86ee5e82018-04-02 15:33:07 -070056import static org.onlab.util.Tools.readTreeFromStream;
Ray Milkey460f9b02016-03-29 11:56:19 -070057
Ray Milkey4f5de002014-12-17 19:26:11 -080058/**
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -070059 * Query and program flow rules.
Ray Milkey4f5de002014-12-17 19:26:11 -080060 */
61
62@Path("flows")
63public class FlowsWebResource extends AbstractWebResource {
Jian Li9d616492016-03-09 10:52:49 -080064
65 @Context
Jian Licc730a62016-05-10 16:36:16 -070066 private UriInfo uriInfo;
Jian Li9d616492016-03-09 10:52:49 -080067
Jian Licc730a62016-05-10 16:36:16 -070068 private static final String DEVICE_NOT_FOUND = "Device is not found";
69 private static final String FLOW_NOT_FOUND = "Flow is not found";
Jian Li2907ad22016-05-12 23:08:54 -070070 private static final String APP_ID_NOT_FOUND = "Application Id is not found";
Ray Milkey131c0682016-10-18 11:12:50 -070071 private static final String FLOW_ARRAY_REQUIRED = "Flows array was not specified";
Jian Licc730a62016-05-10 16:36:16 -070072 private static final String FLOWS = "flows";
73 private static final String DEVICE_ID = "deviceId";
74 private static final String FLOW_ID = "flowId";
Ray Milkey4f5de002014-12-17 19:26:11 -080075
Ray Milkey4f5de002014-12-17 19:26:11 -080076 /**
Jian Licc730a62016-05-10 16:36:16 -070077 * Gets all flow entries. Returns array of all flow rules in the system.
78 *
79 * @return 200 OK with a collection of flows
Jian Li2907ad22016-05-12 23:08:54 -070080 * @onos.rsModel FlowEntries
Ray Milkey4f5de002014-12-17 19:26:11 -080081 */
82 @GET
83 @Produces(MediaType.APPLICATION_JSON)
84 public Response getFlows() {
jaegonkim0ed64432018-04-29 20:39:50 +090085 ObjectNode root = mapper().createObjectNode();
86 ArrayNode flowsNode = root.putArray(FLOWS);
87 FlowRuleService service = get(FlowRuleService.class);
88 Iterable<Device> devices = get(DeviceService.class).getDevices();
89 for (Device device : devices) {
90 Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
Phaneendra Mandaaec654c2015-09-23 19:02:23 +053091 if (flowEntries != null) {
jaegonkim0ed64432018-04-29 20:39:50 +090092 for (FlowEntry entry : flowEntries) {
Thomas Vachuska8683e012015-03-18 18:03:33 -070093 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
Ray Milkey4f5de002014-12-17 19:26:11 -080094 }
95 }
96 }
97
Ray Milkey3f025692015-01-26 11:15:41 -080098 return ok(root).build();
Ray Milkey4f5de002014-12-17 19:26:11 -080099 }
100
rsahot0360f9564d2018-04-30 16:25:05 -0400101 /**
102 * Gets all pending flow entries. Returns array of all pending flow rules in the system.
103 *
104 * @return 200 OK with a collection of flows
105 * @onos.rsModel FlowEntries
106 */
107 @GET
108 @Produces(MediaType.APPLICATION_JSON)
109 @Path("pending")
110 public Response getPendingFlows() {
jaegonkim0ed64432018-04-29 20:39:50 +0900111 ObjectNode root = mapper().createObjectNode();
112 ArrayNode flowsNode = root.putArray(FLOWS);
113 FlowRuleService service = get(FlowRuleService.class);
114 Iterable<Device> devices = get(DeviceService.class).getDevices();
115 for (Device device : devices) {
116 Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
rsahot0360f9564d2018-04-30 16:25:05 -0400117 if (flowEntries != null) {
jaegonkim0ed64432018-04-29 20:39:50 +0900118 for (FlowEntry entry : flowEntries) {
rsahot0360f9564d2018-04-30 16:25:05 -0400119 if ((entry.state() == FlowEntry.FlowEntryState.PENDING_ADD) ||
120 (entry.state() == FlowEntry.FlowEntryState.PENDING_REMOVE)) {
121 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
122 }
123 }
124 }
125 }
126
127 return ok(root).build();
128 }
129
rsahot0362c2c6cc2018-06-22 14:35:07 -0400130 /**
131 * Gets all flow entries for a table. Returns array of all flow rules for a table.
132 * @param tableId table identifier
133 * @return 200 OK with a collection of flows
134 * @onos.rsModel FlowEntries
135 */
136 @GET
137 @Produces(MediaType.APPLICATION_JSON)
138 @Path("table/{tableId}")
139 public Response getTableFlows(@PathParam("tableId") int tableId) {
jaegonkim0ed64432018-04-29 20:39:50 +0900140 ObjectNode root = mapper().createObjectNode();
141 ArrayNode flowsNode = root.putArray(FLOWS);
142 FlowRuleService service = get(FlowRuleService.class);
143 Iterable<Device> devices = get(DeviceService.class).getDevices();
144 for (Device device : devices) {
145 Iterable<FlowEntry> flowEntries = service.getFlowEntries(device.id());
rsahot0362c2c6cc2018-06-22 14:35:07 -0400146 if (flowEntries != null) {
jaegonkim0ed64432018-04-29 20:39:50 +0900147 for (FlowEntry entry : flowEntries) {
rsahot0362c2c6cc2018-06-22 14:35:07 -0400148 if (((IndexTableId) entry.table()).id() == tableId) {
149 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
150 }
151 }
152 }
153 }
154
155 return ok(root).build();
156 }
157
Ray Milkey4f5de002014-12-17 19:26:11 -0800158 /**
Jian Licc730a62016-05-10 16:36:16 -0700159 * Creates new flow rules. Creates and installs a new flow rules.<br>
Jonathan Hartf09a13a2017-01-26 09:52:14 -0800160 * Flow rule criteria and instruction description:
161 * https://wiki.onosproject.org/display/ONOS/Flow+Rules
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700162 *
Ray Milkeybb23e0b2016-08-02 17:00:21 -0700163 * @param appId application id
Jian Licc730a62016-05-10 16:36:16 -0700164 * @param stream flow rules JSON
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700165 * @return status of the request - CREATED if the JSON is correct,
166 * BAD_REQUEST if the JSON is invalid
Jian Licc730a62016-05-10 16:36:16 -0700167 * @onos.rsModel FlowsBatchPost
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700168 */
169 @POST
170 @Consumes(MediaType.APPLICATION_JSON)
171 @Produces(MediaType.APPLICATION_JSON)
Jian Li2907ad22016-05-12 23:08:54 -0700172 public Response createFlows(@QueryParam("appId") String appId, InputStream stream) {
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500173 FlowRuleService service = get(FlowRuleService.class);
jaegonkim0ed64432018-04-29 20:39:50 +0900174 ObjectNode root = mapper().createObjectNode();
175 ArrayNode flowsNode = root.putArray(FLOWS);
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700176 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700177 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Ray Milkey131c0682016-10-18 11:12:50 -0700178 ArrayNode flowsArray = nullIsIllegal((ArrayNode) jsonTree.get(FLOWS),
179 FLOW_ARRAY_REQUIRED);
Jian Li2907ad22016-05-12 23:08:54 -0700180
Jonathan Hart9b80da82016-11-10 21:46:15 +0000181 if (appId != null) {
182 flowsArray.forEach(flowJson -> ((ObjectNode) flowJson).put("appId", appId));
183 }
Jian Li2907ad22016-05-12 23:08:54 -0700184
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700185 List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);
Ray Milkey131c0682016-10-18 11:12:50 -0700186
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500187 service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
Ray Milkey460f9b02016-03-29 11:56:19 -0700188 rules.forEach(flowRule -> {
189 ObjectNode flowNode = mapper().createObjectNode();
190 flowNode.put(DEVICE_ID, flowRule.deviceId().toString())
Jayasree Ghosh28e1b3e2016-06-16 05:38:50 +0530191 .put(FLOW_ID, Long.toString(flowRule.id().value()));
Ray Milkey460f9b02016-03-29 11:56:19 -0700192 flowsNode.add(flowNode);
193 });
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700194 } catch (IOException ex) {
195 throw new IllegalArgumentException(ex);
196 }
Ray Milkey460f9b02016-03-29 11:56:19 -0700197 return Response.ok(root).build();
Thomas Vachuskaa1ae5e12016-03-28 10:36:30 -0700198 }
199
200 /**
Jian Licc730a62016-05-10 16:36:16 -0700201 * Gets flow entries of a device. Returns array of all flow rules for the
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700202 * specified device.
Jian Licc730a62016-05-10 16:36:16 -0700203 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700204 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -0700205 * @return 200 OK with a collection of flows of given device
Jian Li2907ad22016-05-12 23:08:54 -0700206 * @onos.rsModel FlowEntries
Ray Milkey4f5de002014-12-17 19:26:11 -0800207 */
208 @GET
209 @Produces(MediaType.APPLICATION_JSON)
Jian Li2907ad22016-05-12 23:08:54 -0700210 // TODO: we need to add "/device" suffix to the path to differentiate with appId
Ray Milkey4f5de002014-12-17 19:26:11 -0800211 @Path("{deviceId}")
212 public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500213 FlowRuleService service = get(FlowRuleService.class);
jaegonkim0ed64432018-04-29 20:39:50 +0900214 ObjectNode root = mapper().createObjectNode();
215 ArrayNode flowsNode = root.putArray(FLOWS);
216 Iterable<FlowEntry> flowEntries =
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500217 service.getFlowEntries(DeviceId.deviceId(deviceId));
Ray Milkey4f5de002014-12-17 19:26:11 -0800218
Jian Li9d616492016-03-09 10:52:49 -0800219 if (flowEntries == null || !flowEntries.iterator().hasNext()) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800220 throw new ItemNotFoundException(DEVICE_NOT_FOUND);
221 }
jaegonkim0ed64432018-04-29 20:39:50 +0900222 for (FlowEntry entry : flowEntries) {
Thomas Vachuska8683e012015-03-18 18:03:33 -0700223 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
Ray Milkey4f5de002014-12-17 19:26:11 -0800224 }
Ray Milkey3f025692015-01-26 11:15:41 -0800225 return ok(root).build();
Ray Milkey4f5de002014-12-17 19:26:11 -0800226 }
227
228 /**
Jian Li2907ad22016-05-12 23:08:54 -0700229 * Gets flow rules. Returns the flow entry specified by the device id and
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700230 * flow rule id.
Jian Licc730a62016-05-10 16:36:16 -0700231 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700232 * @param deviceId device identifier
233 * @param flowId flow rule identifier
Jian Li2907ad22016-05-12 23:08:54 -0700234 * @return 200 OK with a collection of flows of given device and flow
235 * @onos.rsModel FlowEntries
Ray Milkey4f5de002014-12-17 19:26:11 -0800236 */
237 @GET
238 @Produces(MediaType.APPLICATION_JSON)
239 @Path("{deviceId}/{flowId}")
240 public Response getFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
241 @PathParam("flowId") long flowId) {
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500242 FlowRuleService service = get(FlowRuleService.class);
jaegonkim0ed64432018-04-29 20:39:50 +0900243 ObjectNode root = mapper().createObjectNode();
244 ArrayNode flowsNode = root.putArray(FLOWS);
245 Iterable<FlowEntry> flowEntries =
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500246 service.getFlowEntries(DeviceId.deviceId(deviceId));
Ray Milkey4f5de002014-12-17 19:26:11 -0800247
Jian Li9d616492016-03-09 10:52:49 -0800248 if (flowEntries == null || !flowEntries.iterator().hasNext()) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800249 throw new ItemNotFoundException(DEVICE_NOT_FOUND);
250 }
jaegonkim0ed64432018-04-29 20:39:50 +0900251 for (FlowEntry entry : flowEntries) {
Ray Milkey4f5de002014-12-17 19:26:11 -0800252 if (entry.id().value() == flowId) {
Thomas Vachuska8683e012015-03-18 18:03:33 -0700253 flowsNode.add(codec(FlowEntry.class).encode(entry, this));
Ray Milkey4f5de002014-12-17 19:26:11 -0800254 }
255 }
Ray Milkey3f025692015-01-26 11:15:41 -0800256 return ok(root).build();
Ray Milkey4f5de002014-12-17 19:26:11 -0800257 }
Ray Milkeyd43fe452015-05-29 09:35:12 -0700258
259 /**
Jian Li2907ad22016-05-12 23:08:54 -0700260 * Gets flow rules generated by an application.
261 * Returns the flow rule specified by the application id.
262 *
263 * @param appId application identifier
264 * @return 200 OK with a collection of flows of given application id
265 * @onos.rsModel FlowRules
266 */
267 @GET
268 @Produces(MediaType.APPLICATION_JSON)
269 @Path("application/{appId}")
270 public Response getFlowByAppId(@PathParam("appId") String appId) {
jaegonkim0ed64432018-04-29 20:39:50 +0900271 ObjectNode root = mapper().createObjectNode();
272 ArrayNode flowsNode = root.putArray(FLOWS);
273 ApplicationService appService = get(ApplicationService.class);
274 ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
275 Iterable<FlowEntry> flowEntries = get(FlowRuleService.class).getFlowEntriesById(idInstant);
Jian Li2907ad22016-05-12 23:08:54 -0700276
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530277 flowEntries.forEach(flow -> flowsNode.add(codec(FlowEntry.class).encode(flow, this)));
Jian Li2907ad22016-05-12 23:08:54 -0700278 return ok(root).build();
279 }
280
Bharath Thiruveedula99849dc2016-11-17 22:04:38 +0530281
Jian Li2907ad22016-05-12 23:08:54 -0700282 /**
283 * Removes flow rules by application ID.
284 * Removes a collection of flow rules generated by the given application.
285 *
286 * @param appId application identifier
287 * @return 204 NO CONTENT
288 */
289 @DELETE
290 @Produces(MediaType.APPLICATION_JSON)
291 @Path("application/{appId}")
292 public Response removeFlowByAppId(@PathParam("appId") String appId) {
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500293 FlowRuleService service = get(FlowRuleService.class);
jaegonkim0ed64432018-04-29 20:39:50 +0900294 ApplicationService appService = get(ApplicationService.class);
295 ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500296 service.removeFlowRulesById(idInstant);
Jian Li2907ad22016-05-12 23:08:54 -0700297 return Response.noContent().build();
298 }
299
300 /**
Jian Licc730a62016-05-10 16:36:16 -0700301 * Creates new flow rule. Creates and installs a new flow rule for the
Andrea Campanella881f29f2016-03-03 19:18:42 -0800302 * specified device. <br>
Jonathan Hartf09a13a2017-01-26 09:52:14 -0800303 * Flow rule criteria and instruction description:
304 * https://wiki.onosproject.org/display/ONOS/Flow+Rules
Andrea Campanella881f29f2016-03-03 19:18:42 -0800305 *
Madan Jampani0dbac7a2015-06-25 10:37:45 -0700306 * @param deviceId device identifier
Jian Li2907ad22016-05-12 23:08:54 -0700307 * @param appId application identifier
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700308 * @param stream flow rule JSON
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700309 * @return status of the request - CREATED if the JSON is correct,
Ray Milkeyd43fe452015-05-29 09:35:12 -0700310 * BAD_REQUEST if the JSON is invalid
Jian Licc730a62016-05-10 16:36:16 -0700311 * @onos.rsModel FlowsPost
Ray Milkeyd43fe452015-05-29 09:35:12 -0700312 */
313 @POST
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700314 @Path("{deviceId}")
Ray Milkeyd43fe452015-05-29 09:35:12 -0700315 @Consumes(MediaType.APPLICATION_JSON)
316 @Produces(MediaType.APPLICATION_JSON)
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700317 public Response createFlow(@PathParam("deviceId") String deviceId,
Jian Li2907ad22016-05-12 23:08:54 -0700318 @QueryParam("appId") String appId,
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700319 InputStream stream) {
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500320 FlowRuleService service = get(FlowRuleService.class);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700321 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700322 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Ray Milkey5d915f42015-08-13 10:27:53 -0700323 JsonNode specifiedDeviceId = jsonTree.get("deviceId");
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700324 if (specifiedDeviceId != null &&
325 !specifiedDeviceId.asText().equals(deviceId)) {
326 throw new IllegalArgumentException(
327 "Invalid deviceId in flow creation request");
328 }
Ray Milkey5d915f42015-08-13 10:27:53 -0700329 jsonTree.put("deviceId", deviceId);
Jian Li2907ad22016-05-12 23:08:54 -0700330
Jonathan Hart9b80da82016-11-10 21:46:15 +0000331 if (appId != null) {
332 jsonTree.put("appId", appId);
333 }
Jian Li2907ad22016-05-12 23:08:54 -0700334
Ray Milkey5d915f42015-08-13 10:27:53 -0700335 FlowRule rule = codec(FlowRule.class).decode(jsonTree, this);
Harshada Chaundkar4f62a1e2019-02-18 12:27:34 -0500336 service.applyFlowRules(rule);
Jian Li9d616492016-03-09 10:52:49 -0800337 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
338 .path("flows")
339 .path(deviceId)
Ray Milkey90289b02016-03-31 15:23:28 -0700340 .path(Long.toString(rule.id().value()));
Jian Li9d616492016-03-09 10:52:49 -0800341
342 return Response
343 .created(locationBuilder.build())
344 .build();
345 } catch (IOException ex) {
Ray Milkey5d915f42015-08-13 10:27:53 -0700346 throw new IllegalArgumentException(ex);
Ray Milkeyd43fe452015-05-29 09:35:12 -0700347 }
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700348 }
349
350 /**
Jian Li2907ad22016-05-12 23:08:54 -0700351 * Removes flow rule. Removes the specified flow rule.
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700352 *
Thomas Vachuska0fa2aa12015-08-18 12:53:04 -0700353 * @param deviceId device identifier
354 * @param flowId flow rule identifier
Jian Lic2a542b2016-05-10 11:48:19 -0700355 * @return 204 NO CONTENT
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700356 */
357 @DELETE
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700358 @Path("{deviceId}/{flowId}")
Jian Lic2a542b2016-05-10 11:48:19 -0700359 public Response deleteFlowByDeviceIdAndFlowId(@PathParam("deviceId") String deviceId,
Jian Licc730a62016-05-10 16:36:16 -0700360 @PathParam("flowId") long flowId) {
jaegonkim0ed64432018-04-29 20:39:50 +0900361 FlowRuleService service = get(FlowRuleService.class);
362 Iterable<FlowEntry> flowEntries =
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700363 service.getFlowEntries(DeviceId.deviceId(deviceId));
364
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530365 if (!flowEntries.iterator().hasNext()) {
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700366 throw new ItemNotFoundException(DEVICE_NOT_FOUND);
367 }
368
Phaneendra Mandaaec654c2015-09-23 19:02:23 +0530369 StreamSupport.stream(flowEntries.spliterator(), false)
Ray Milkeyeb5c7172015-06-23 14:59:27 -0700370 .filter(entry -> entry.id().value() == flowId)
371 .forEach(service::removeFlowRules);
Jian Lic2a542b2016-05-10 11:48:19 -0700372 return Response.noContent().build();
Ray Milkeyd43fe452015-05-29 09:35:12 -0700373 }
374
Ray Milkey460f9b02016-03-29 11:56:19 -0700375 /**
376 * Removes a batch of flow rules.
Ray Milkeybee35092016-04-12 10:01:26 -0700377 *
378 * @param stream stream for posted JSON
Jian Licc730a62016-05-10 16:36:16 -0700379 * @return 204 NO CONTENT
Ray Milkey460f9b02016-03-29 11:56:19 -0700380 */
381 @DELETE
Jian Lic2a542b2016-05-10 11:48:19 -0700382 public Response deleteFlows(InputStream stream) {
jaegonkim0ed64432018-04-29 20:39:50 +0900383 FlowRuleService service = get(FlowRuleService.class);
Ray Milkey460f9b02016-03-29 11:56:19 -0700384 ListMultimap<DeviceId, Long> deviceMap = ArrayListMultimap.create();
385 List<FlowEntry> rulesToRemove = new ArrayList<>();
386
387 try {
Ray Milkey86ee5e82018-04-02 15:33:07 -0700388 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Ray Milkey460f9b02016-03-29 11:56:19 -0700389
390 JsonNode jsonFlows = jsonTree.get("flows");
391
392 jsonFlows.forEach(node -> {
393 DeviceId deviceId =
394 DeviceId.deviceId(
395 nullIsNotFound(node.get(DEVICE_ID),
Jian Licc730a62016-05-10 16:36:16 -0700396 DEVICE_NOT_FOUND).asText());
Ray Milkey460f9b02016-03-29 11:56:19 -0700397 long flowId = nullIsNotFound(node.get(FLOW_ID),
Jian Licc730a62016-05-10 16:36:16 -0700398 FLOW_NOT_FOUND).asLong();
Ray Milkey460f9b02016-03-29 11:56:19 -0700399 deviceMap.put(deviceId, flowId);
400
401 });
402 } catch (IOException ex) {
403 throw new IllegalArgumentException(ex);
404 }
405
406 deviceMap.keySet().forEach(deviceId -> {
407 List<Long> flowIds = deviceMap.get(deviceId);
408 Iterable<FlowEntry> entries = service.getFlowEntries(deviceId);
409 flowIds.forEach(flowId -> {
410 StreamSupport.stream(entries.spliterator(), false)
411 .filter(entry -> flowId == entry.id().value())
412 .forEach(rulesToRemove::add);
413 });
414 });
415
416 service.removeFlowRules(rulesToRemove.toArray(new FlowEntry[0]));
Jian Lic2a542b2016-05-10 11:48:19 -0700417 return Response.noContent().build();
Ray Milkey460f9b02016-03-29 11:56:19 -0700418 }
Ray Milkey4f5de002014-12-17 19:26:11 -0800419}