blob: 5b4e28600efd10063c1f6bad2d9c3d6bb3543d2e [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Ray Milkey34c95902015-04-15 09:47:53 -07002 * Copyright 2014-2015 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.of.flow.impl;
alshabib1cc04f72014-09-16 16:09:58 -070017
Jonathan Hart2ffcd102015-01-16 16:47:50 -080018
Brian O'Connor72cb19a2015-01-16 16:14:41 -080019import com.google.common.cache.Cache;
20import com.google.common.cache.CacheBuilder;
21import com.google.common.cache.RemovalCause;
22import com.google.common.cache.RemovalNotification;
23import com.google.common.collect.Maps;
24import com.google.common.collect.Sets;
alshabib1cc04f72014-09-16 16:09:58 -070025import org.apache.felix.scr.annotations.Activate;
26import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.net.DeviceId;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.flow.CompletedBatchOperation;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.flow.FlowEntry;
34import org.onosproject.net.flow.FlowRule;
35import org.onosproject.net.flow.FlowRuleBatchEntry;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080036import org.onosproject.net.flow.FlowRuleBatchOperation;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.flow.FlowRuleProvider;
38import org.onosproject.net.flow.FlowRuleProviderRegistry;
39import org.onosproject.net.flow.FlowRuleProviderService;
40import org.onosproject.net.provider.AbstractProvider;
41import org.onosproject.net.provider.ProviderId;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.openflow.controller.Dpid;
43import org.onosproject.openflow.controller.OpenFlowController;
44import org.onosproject.openflow.controller.OpenFlowEventListener;
45import org.onosproject.openflow.controller.OpenFlowSwitch;
46import org.onosproject.openflow.controller.OpenFlowSwitchListener;
47import org.onosproject.openflow.controller.RoleState;
alshabib902d41b2014-10-07 16:52:05 -070048import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
49import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080050import org.projectfloodlight.openflow.protocol.OFErrorType;
alshabib193525b2014-10-08 18:58:03 -070051import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070052import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070053import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib8f1cf4a2014-09-17 14:44:48 -070054import org.projectfloodlight.openflow.protocol.OFMessage;
55import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070056import org.projectfloodlight.openflow.protocol.OFStatsReply;
sangho89bf6fb2015-02-09 09:33:13 -080057import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabib193525b2014-10-08 18:58:03 -070058import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib1cc04f72014-09-16 16:09:58 -070059import org.slf4j.Logger;
60
Brian O'Connor72cb19a2015-01-16 16:14:41 -080061import java.util.Collections;
62import java.util.List;
63import java.util.Map;
64import java.util.Optional;
65import java.util.Set;
66import java.util.concurrent.TimeUnit;
67import java.util.stream.Collectors;
68
69import static org.slf4j.LoggerFactory.getLogger;
70
alshabibeec3a062014-09-17 18:01:26 -070071
alshabib1cc04f72014-09-16 16:09:58 -070072/**
73 * Provider which uses an OpenFlow controller to detect network
74 * end-station hosts.
75 */
76@Component(immediate = true)
77public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
78
79 private final Logger log = getLogger(getClass());
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected FlowRuleProviderRegistry providerRegistry;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected OpenFlowController controller;
86
alshabib1cc04f72014-09-16 16:09:58 -070087
88 private FlowRuleProviderService providerService;
89
alshabibeec3a062014-09-17 18:01:26 -070090 private final InternalFlowProvider listener = new InternalFlowProvider();
91
Brian O'Connor72cb19a2015-01-16 16:14:41 -080092 private Cache<Long, InternalCacheEntry> pendingBatches;
alshabib193525b2014-10-08 18:58:03 -070093
alshabib3d643ec2014-10-22 18:33:00 -070094 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
95
Thomas Vachuska9b2da212014-11-10 19:30:25 -080096
alshabib1cc04f72014-09-16 16:09:58 -070097 /**
98 * Creates an OpenFlow host provider.
99 */
100 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800101 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700102 }
103
104 @Activate
105 public void activate() {
106 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700107 controller.addListener(listener);
108 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700109
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800110 pendingBatches = CacheBuilder.newBuilder()
111 .expireAfterWrite(10, TimeUnit.SECONDS)
112 .removalListener((RemovalNotification<Long, InternalCacheEntry> notification) -> {
113 if (notification.getCause() == RemovalCause.EXPIRED) {
114 providerService.batchOperationCompleted(notification.getKey(),
115 notification.getValue().failedCompletion());
116 }
117 }).build();
118
119
alshabib3d643ec2014-10-22 18:33:00 -0700120 for (OpenFlowSwitch sw : controller.getSwitches()) {
121 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
122 fsc.start();
123 collectors.put(new Dpid(sw.getId()), fsc);
124 }
125
126
alshabib1cc04f72014-09-16 16:09:58 -0700127 log.info("Started");
128 }
129
130 @Deactivate
131 public void deactivate() {
132 providerRegistry.unregister(this);
133 providerService = null;
134
135 log.info("Stopped");
136 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800137
alshabib1cc04f72014-09-16 16:09:58 -0700138 @Override
139 public void applyFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800140 for (FlowRule flowRule : flowRules) {
141 applyRule(flowRule);
alshabib35edb1a2014-09-16 17:44:44 -0700142 }
alshabib1cc04f72014-09-16 16:09:58 -0700143 }
144
alshabib35edb1a2014-09-16 17:44:44 -0700145 private void applyRule(FlowRule flowRule) {
146 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
alshabib08d98982015-04-21 16:25:50 -0700147 if (flowRule.tableId() == 0) {
sangho87af8112015-01-29 12:53:08 -0800148 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
149 Optional.empty()).buildFlowAdd());
150 } else {
alshabib08d98982015-04-21 16:25:50 -0700151 OpenFlowSwitch.TableType type = getTableType(flowRule.tableId());
Saurav Dasfa2fa932015-03-03 11:29:48 -0800152 sw.transformAndSendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
alshabib9af70072015-02-09 14:34:16 -0800153 Optional.empty()).buildFlowAdd(),
154 type);
sangho87af8112015-01-29 12:53:08 -0800155 }
alshabib35edb1a2014-09-16 17:44:44 -0700156 }
157
alshabib35edb1a2014-09-16 17:44:44 -0700158
alshabib1cc04f72014-09-16 16:09:58 -0700159 @Override
160 public void removeFlowRule(FlowRule... flowRules) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800161 for (FlowRule flowRule : flowRules) {
162 removeRule(flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700163 }
alshabib1cc04f72014-09-16 16:09:58 -0700164
165 }
166
alshabib219ebaa2014-09-22 15:41:24 -0700167 private void removeRule(FlowRule flowRule) {
168 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
alshabib08d98982015-04-21 16:25:50 -0700169 if (flowRule.tableId() == 0) {
sangho87af8112015-01-29 12:53:08 -0800170 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
171 Optional.empty()).buildFlowDel());
172 } else {
Saurav Dasfa2fa932015-03-03 11:29:48 -0800173 sw.transformAndSendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
alshabib08d98982015-04-21 16:25:50 -0700174 Optional.empty()).buildFlowDel(), getTableType(flowRule.tableId()));
sangho87af8112015-01-29 12:53:08 -0800175 }
alshabib219ebaa2014-09-22 15:41:24 -0700176 }
177
alshabiba68eb962014-09-24 20:34:13 -0700178 @Override
179 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
180 // TODO: optimize using the ApplicationId
181 removeFlowRule(flowRules);
182 }
183
alshabib193525b2014-10-08 18:58:03 -0700184 @Override
sangho87af8112015-01-29 12:53:08 -0800185
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800186 public void executeBatch(FlowRuleBatchOperation batch) {
187
188 pendingBatches.put(batch.id(), new InternalCacheEntry(batch));
189
190
191 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(batch.deviceId().uri()));
192 OFFlowMod mod;
193
alshabib193525b2014-10-08 18:58:03 -0700194 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800195
Brian O'Connor427a1762014-11-19 18:40:32 -0800196 FlowModBuilder builder =
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800197 FlowModBuilder.builder(fbe.target(), sw.factory(),
198 Optional.of(batch.id()));
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800199 switch (fbe.operator()) {
alshabib193525b2014-10-08 18:58:03 -0700200 case ADD:
201 mod = builder.buildFlowAdd();
202 break;
203 case REMOVE:
204 mod = builder.buildFlowDel();
205 break;
206 case MODIFY:
207 mod = builder.buildFlowMod();
208 break;
209 default:
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800210 log.error("Unsupported batch operation {}; skipping flowmod {}",
211 fbe.operator(), fbe);
212 continue;
213 }
Saurav Das3ea46622015-04-22 14:01:34 -0700214 /*if (fbe.target().tableId() == 0) {
sangho22a805d2015-02-13 09:45:43 -0800215 sw.sendMsg(mod);
216 } else {
alshabib08d98982015-04-21 16:25:50 -0700217 sw.transformAndSendMsg(mod, getTableType(fbe.target().tableId()));
Saurav Das3ea46622015-04-22 14:01:34 -0700218 }*/
219 sw.sendMsg(mod);
alshabib193525b2014-10-08 18:58:03 -0700220 }
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800221 OFBarrierRequest.Builder builder = sw.factory()
222 .buildBarrierRequest()
223 .setXid(batch.id());
224 sw.sendMsg(builder.build());
alshabib193525b2014-10-08 18:58:03 -0700225 }
226
alshabib08d98982015-04-21 16:25:50 -0700227 private OpenFlowSwitch.TableType getTableType(int type) {
228 switch (FlowRule.Type.values()[type]) {
alshabib9af70072015-02-09 14:34:16 -0800229
230 case DEFAULT:
231 return OpenFlowSwitch.TableType.NONE;
sangho87af8112015-01-29 12:53:08 -0800232 case IP:
233 return OpenFlowSwitch.TableType.IP;
234 case MPLS:
235 return OpenFlowSwitch.TableType.MPLS;
236 case ACL:
237 return OpenFlowSwitch.TableType.ACL;
alshabib9af70072015-02-09 14:34:16 -0800238 case VLAN_MPLS:
239 return OpenFlowSwitch.TableType.VLAN_MPLS;
240 case VLAN:
241 return OpenFlowSwitch.TableType.VLAN;
242 case ETHER:
243 return OpenFlowSwitch.TableType.ETHER;
244 case COS:
245 return OpenFlowSwitch.TableType.COS;
Saurav Dasfa2fa932015-03-03 11:29:48 -0800246 case FIRST:
247 return OpenFlowSwitch.TableType.FIRST;
sangho87af8112015-01-29 12:53:08 -0800248 default:
249 return OpenFlowSwitch.TableType.NONE;
250 }
251 }
alshabib193525b2014-10-08 18:58:03 -0700252
Saurav Dasfa2fa932015-03-03 11:29:48 -0800253 private FlowRule.Type getType(OpenFlowSwitch.TableType tableType) {
254 switch (tableType) {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800255
Saurav Dasfa2fa932015-03-03 11:29:48 -0800256 case NONE:
257 return FlowRule.Type.DEFAULT;
258 case IP:
259 return FlowRule.Type.IP;
260 case MPLS:
261 return FlowRule.Type.MPLS;
262 case ACL:
263 return FlowRule.Type.ACL;
264 case VLAN_MPLS:
265 return FlowRule.Type.VLAN_MPLS;
266 case VLAN:
267 return FlowRule.Type.VLAN;
268 case ETHER:
269 return FlowRule.Type.ETHER;
270 case COS:
271 return FlowRule.Type.COS;
272 case FIRST:
273 return FlowRule.Type.FIRST;
274 default:
275 return FlowRule.Type.DEFAULT;
276 }
277 }
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800278
279
alshabib8f1cf4a2014-09-17 14:44:48 -0700280 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800281 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700282
alshabib8f1cf4a2014-09-17 14:44:48 -0700283 @Override
284 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700285 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700286 fsc.start();
287 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700288 }
289
290 @Override
291 public void switchRemoved(Dpid dpid) {
alshabibdfc7afb2014-10-21 20:13:27 -0700292 FlowStatsCollector collector = collectors.remove(dpid);
293 if (collector != null) {
294 collector.stop();
295 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700296 }
297
298 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700299 public void switchChanged(Dpid dpid) {
300 }
301
302 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700303 public void portChanged(Dpid dpid, OFPortStatus status) {
304 //TODO: Decide whether to evict flows internal store.
305 }
306
307 @Override
308 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabibda1644e2015-03-13 14:01:35 -0700309 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib8f1cf4a2014-09-17 14:44:48 -0700310 switch (msg.getType()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800311 case FLOW_REMOVED:
312 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700313
alshabibda1644e2015-03-13 14:01:35 -0700314 FlowEntry fr = new FlowEntryBuilder(dpid, removed,
315 getType(sw.getTableType(removed.getTableId()))).build();
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800316 providerService.flowRemoved(fr);
317 break;
318 case STATS_REPLY:
sangho20f91162015-02-12 11:24:23 -0800319 if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) {
sangho89bf6fb2015-02-09 09:33:13 -0800320 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
321 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800322 break;
323 case BARRIER_REPLY:
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800324 try {
325 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
326 if (entry != null) {
327 providerService.batchOperationCompleted(msg.getXid(), entry.completed());
328 } else {
329 log.warn("Received unknown Barrier Reply: {}", msg.getXid());
330 }
331 } finally {
332 pendingBatches.invalidate(msg.getXid());
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800333 }
334 break;
335 case ERROR:
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800336 log.warn("received Error message {} from {}", msg, dpid);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800337
338 OFErrorMsg error = (OFErrorMsg) msg;
339 if (error.getErrType() == OFErrorType.FLOW_MOD_FAILED) {
340 OFFlowModFailedErrorMsg fmFailed = (OFFlowModFailedErrorMsg) error;
341 if (fmFailed.getData().getParsedMessage().isPresent()) {
342 OFMessage m = fmFailed.getData().getParsedMessage().get();
343 OFFlowMod fm = (OFFlowMod) m;
344 InternalCacheEntry entry = pendingBatches.getIfPresent(msg.getXid());
345 if (entry != null) {
alshabibda1644e2015-03-13 14:01:35 -0700346 entry.appendFailure(new FlowEntryBuilder(dpid, fm,
347 getType(sw.getTableType(fm.getTableId())))
348 .build());
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800349 } else {
350 log.error("No matching batch for this error: {}", error);
351 }
352 } else {
353 //FIXME: Potentially add flowtracking to avoid this message.
354 log.error("Flow installation failed but switch didn't" +
355 " tell us which one.");
356 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800357 } else {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800358 log.warn("Received error {}", error);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800359 }
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800360
361
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800362 default:
363 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700364 }
365
366 }
367
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700368 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700369 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800370 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700371 // Do nothing here for now.
372 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700373
sangho89bf6fb2015-02-09 09:33:13 -0800374 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800375
alshabib54ce5892014-09-23 17:50:51 -0700376 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
Saurav Dasfa2fa932015-03-03 11:29:48 -0800377 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib54ce5892014-09-23 17:50:51 -0700378
alshabib64def642014-12-02 23:27:37 -0800379 List<FlowEntry> flowEntries = replies.getEntries().stream()
Saurav Dasfa2fa932015-03-03 11:29:48 -0800380 .map(entry -> new FlowEntryBuilder(dpid, entry,
381 getType(sw.getTableType(entry.getTableId())))
382 .build())
alshabib64def642014-12-02 23:27:37 -0800383 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700384
alshabib64def642014-12-02 23:27:37 -0800385 providerService.pushFlowMetrics(did, flowEntries);
386
alshabib5c370ff2014-09-18 10:12:14 -0700387 }
388
alshabib8f1cf4a2014-09-17 14:44:48 -0700389 }
alshabib1cc04f72014-09-16 16:09:58 -0700390
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800391 /**
392 * The internal cache entry holding the original request as well
393 * as accumulating the any failures along the way.
394 *
395 * If this entry is evicted from the cache then the entire operation
396 * is considered failed. Otherwise, only the failures reported by the device
397 * will be propagated up.
398 */
399 private class InternalCacheEntry {
alshabib902d41b2014-10-07 16:52:05 -0700400
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800401 private final FlowRuleBatchOperation operation;
402 private final Set<FlowRule> failures = Sets.newConcurrentHashSet();
alshabib193525b2014-10-08 18:58:03 -0700403
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800404 public InternalCacheEntry(FlowRuleBatchOperation operation) {
405 this.operation = operation;
alshabib902d41b2014-10-07 16:52:05 -0700406 }
407
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800408 /**
409 * Appends a failed rule to the set of failed items.
410 * @param rule the failed rule
411 */
412 public void appendFailure(FlowRule rule) {
413 failures.add(rule);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800414 }
415
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800416 /**
417 * Fails the entire batch and returns the failed operation.
418 * @return the failed operation
419 */
420 public CompletedBatchOperation failedCompletion() {
421 Set<FlowRule> fails = operation.getOperations().stream()
422 .map(op -> op.target()).collect(Collectors.toSet());
423 return new CompletedBatchOperation(false, Collections.unmodifiableSet(fails), operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700424 }
425
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800426 /**
427 * Returns the completed operation and whether the batch suceeded.
428 * @return the completed operation
429 */
430 public CompletedBatchOperation completed() {
431 return new CompletedBatchOperation(failures.isEmpty(),
432 Collections.unmodifiableSet(failures), operation.deviceId());
alshabib902d41b2014-10-07 16:52:05 -0700433 }
434
alshabib902d41b2014-10-07 16:52:05 -0700435 }
alshabiba68eb962014-09-24 20:34:13 -0700436
alshabib1cc04f72014-09-16 16:09:58 -0700437}