blob: 0744b1b729262f10f823fae66d602c9db06e8b66 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 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
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080018import com.google.common.base.MoreObjects;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080019import com.google.common.collect.ArrayListMultimap;
20import com.google.common.collect.Maps;
21import com.google.common.collect.Multimap;
22import com.google.common.collect.Sets;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080023
alshabib1cc04f72014-09-16 16:09:58 -070024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
27import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connorabafb502014-12-02 22:26:20 -080029import org.onosproject.core.ApplicationId;
30import org.onosproject.net.DeviceId;
31import org.onosproject.net.flow.BatchOperation;
32import org.onosproject.net.flow.CompletedBatchOperation;
33import org.onosproject.net.flow.DefaultFlowEntry;
34import org.onosproject.net.flow.FlowEntry;
35import org.onosproject.net.flow.FlowRule;
36import org.onosproject.net.flow.FlowRuleBatchEntry;
37import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
38import org.onosproject.net.flow.FlowRuleProvider;
39import org.onosproject.net.flow.FlowRuleProviderRegistry;
40import org.onosproject.net.flow.FlowRuleProviderService;
41import org.onosproject.net.provider.AbstractProvider;
42import org.onosproject.net.provider.ProviderId;
43import org.onosproject.net.topology.TopologyService;
44import org.onosproject.openflow.controller.Dpid;
45import org.onosproject.openflow.controller.OpenFlowController;
46import org.onosproject.openflow.controller.OpenFlowEventListener;
47import org.onosproject.openflow.controller.OpenFlowSwitch;
48import org.onosproject.openflow.controller.OpenFlowSwitchListener;
49import org.onosproject.openflow.controller.RoleState;
alshabib19fdc122014-10-03 11:38:19 -070050import org.projectfloodlight.openflow.protocol.OFActionType;
alshabib902d41b2014-10-07 16:52:05 -070051import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
52import org.projectfloodlight.openflow.protocol.OFErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070053import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070054import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070055import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
56import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070057import org.projectfloodlight.openflow.protocol.OFInstructionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070058import org.projectfloodlight.openflow.protocol.OFMessage;
59import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070060import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070061import org.projectfloodlight.openflow.protocol.OFVersion;
62import org.projectfloodlight.openflow.protocol.action.OFAction;
63import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
alshabib193525b2014-10-08 18:58:03 -070064import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
65import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
66import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
67import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
68import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib19fdc122014-10-03 11:38:19 -070069import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
70import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
71import org.projectfloodlight.openflow.types.OFPort;
alshabib1cc04f72014-09-16 16:09:58 -070072import org.slf4j.Logger;
73
Thomas Vachuska9b2da212014-11-10 19:30:25 -080074import java.util.Collections;
75import java.util.HashMap;
76import java.util.List;
77import java.util.Map;
Brian O'Connor427a1762014-11-19 18:40:32 -080078import java.util.Optional;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080079import java.util.Set;
80import java.util.concurrent.ConcurrentHashMap;
81import java.util.concurrent.CountDownLatch;
82import java.util.concurrent.ExecutionException;
83import java.util.concurrent.Future;
84import java.util.concurrent.TimeUnit;
85import java.util.concurrent.TimeoutException;
86import java.util.concurrent.atomic.AtomicBoolean;
87import java.util.concurrent.atomic.AtomicLong;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080088import java.util.stream.Collectors;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080089
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080090import static com.google.common.base.Preconditions.checkState;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080091import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070092
alshabib1cc04f72014-09-16 16:09:58 -070093/**
94 * Provider which uses an OpenFlow controller to detect network
95 * end-station hosts.
96 */
97@Component(immediate = true)
98public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
99
alshabib193525b2014-10-08 18:58:03 -0700100 enum BatchState { STARTED, FINISHED, CANCELLED };
101
alshabib1cc04f72014-09-16 16:09:58 -0700102 private final Logger log = getLogger(getClass());
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected FlowRuleProviderRegistry providerRegistry;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected OpenFlowController controller;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected TopologyService topologyService;
112
113 private FlowRuleProviderService providerService;
114
alshabibeec3a062014-09-17 18:01:26 -0700115 private final InternalFlowProvider listener = new InternalFlowProvider();
116
Madan Jampani117aaae2014-10-23 10:04:05 -0700117 // FIXME: This should be an expiring map to ensure futures that don't have
118 // a future eventually get garbage collected.
alshabib902d41b2014-10-07 16:52:05 -0700119 private final Map<Long, InstallationFuture> pendingFutures =
120 new ConcurrentHashMap<Long, InstallationFuture>();
121
alshabib193525b2014-10-08 18:58:03 -0700122 private final Map<Long, InstallationFuture> pendingFMs =
123 new ConcurrentHashMap<Long, InstallationFuture>();
124
alshabib3d643ec2014-10-22 18:33:00 -0700125 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
126
Brian O'Connor427a1762014-11-19 18:40:32 -0800127 private final AtomicLong xidCounter = new AtomicLong(1);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800128
alshabib1cc04f72014-09-16 16:09:58 -0700129 /**
130 * Creates an OpenFlow host provider.
131 */
132 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800133 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700134 }
135
136 @Activate
137 public void activate() {
138 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700139 controller.addListener(listener);
140 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700141
142 for (OpenFlowSwitch sw : controller.getSwitches()) {
143 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
144 fsc.start();
145 collectors.put(new Dpid(sw.getId()), fsc);
146 }
147
148
alshabib1cc04f72014-09-16 16:09:58 -0700149 log.info("Started");
150 }
151
152 @Deactivate
153 public void deactivate() {
154 providerRegistry.unregister(this);
155 providerService = null;
156
157 log.info("Stopped");
158 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800159
alshabib1cc04f72014-09-16 16:09:58 -0700160 @Override
161 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -0700162 for (int i = 0; i < flowRules.length; i++) {
163 applyRule(flowRules[i]);
164 }
alshabib1cc04f72014-09-16 16:09:58 -0700165 }
166
alshabib35edb1a2014-09-16 17:44:44 -0700167 private void applyRule(FlowRule flowRule) {
168 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800169 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
170 Optional.empty()).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700171 }
172
alshabib35edb1a2014-09-16 17:44:44 -0700173
alshabib1cc04f72014-09-16 16:09:58 -0700174 @Override
175 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700176 for (int i = 0; i < flowRules.length; i++) {
177 removeRule(flowRules[i]);
178 }
alshabib1cc04f72014-09-16 16:09:58 -0700179
180 }
181
alshabib219ebaa2014-09-22 15:41:24 -0700182 private void removeRule(FlowRule flowRule) {
183 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800184 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
185 Optional.empty()).buildFlowDel());
alshabib219ebaa2014-09-22 15:41:24 -0700186 }
187
alshabiba68eb962014-09-24 20:34:13 -0700188 @Override
189 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
190 // TODO: optimize using the ApplicationId
191 removeFlowRule(flowRules);
192 }
193
alshabib193525b2014-10-08 18:58:03 -0700194 @Override
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800195 public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800196 final Set<Dpid> sws = Sets.newConcurrentHashSet();
197 final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>();
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800198 /*
199 * Use identity hash map for reference equality as we could have equal
200 * flow mods for different switches.
201 */
202 Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
alshabib193525b2014-10-08 18:58:03 -0700203 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
204 FlowRule flowRule = fbe.getTarget();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800205 final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
206 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib7911a052014-10-16 17:49:37 -0700207 if (sw == null) {
alshabib3effd042014-10-17 12:00:31 -0700208 /*
209 * if a switch we are supposed to install to is gone then
210 * cancel (ie. rollback) the work that has been done so far
211 * and return the associated future.
212 */
213 InstallationFuture failed = new InstallationFuture(sws, fmXids);
214 failed.cancel(true);
215 return failed;
alshabib7911a052014-10-16 17:49:37 -0700216 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800217 sws.add(dpid);
218 final Long flowModXid = xidCounter.getAndIncrement();
Brian O'Connor427a1762014-11-19 18:40:32 -0800219 FlowModBuilder builder =
220 FlowModBuilder.builder(flowRule, sw.factory(),
221 Optional.of(flowModXid));
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800222 OFFlowMod mod = null;
alshabib193525b2014-10-08 18:58:03 -0700223 switch (fbe.getOperator()) {
224 case ADD:
225 mod = builder.buildFlowAdd();
226 break;
227 case REMOVE:
228 mod = builder.buildFlowDel();
229 break;
230 case MODIFY:
231 mod = builder.buildFlowMod();
232 break;
233 default:
234 log.error("Unsupported batch operation {}", fbe.getOperator());
235 }
236 if (mod != null) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800237 mods.put(mod, sw);
Brian O'Connor427a1762014-11-19 18:40:32 -0800238 fmXids.put(flowModXid, fbe);
alshabib193525b2014-10-08 18:58:03 -0700239 } else {
240 log.error("Conversion of flowrule {} failed.", flowRule);
241 }
alshabib193525b2014-10-08 18:58:03 -0700242 }
243 InstallationFuture installation = new InstallationFuture(sws, fmXids);
244 for (Long xid : fmXids.keySet()) {
245 pendingFMs.put(xid, installation);
246 }
Brian O'Connor427a1762014-11-19 18:40:32 -0800247
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800248 pendingFutures.put(installation.xid(), installation);
249 for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
250 OpenFlowSwitch sw = entry.getValue();
251 OFFlowMod mod = entry.getKey();
252 sw.sendMsg(mod);
253 }
254 installation.verify();
alshabib193525b2014-10-08 18:58:03 -0700255 return installation;
256 }
257
258
alshabib8f1cf4a2014-09-17 14:44:48 -0700259 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800260 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700261
alshabib3d643ec2014-10-22 18:33:00 -0700262
alshabib1c319ff2014-10-04 20:29:09 -0700263 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700264 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700265
266 @Override
267 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700268 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700269 fsc.start();
270 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700271 }
272
273 @Override
274 public void switchRemoved(Dpid dpid) {
alshabibdfc7afb2014-10-21 20:13:27 -0700275 FlowStatsCollector collector = collectors.remove(dpid);
276 if (collector != null) {
277 collector.stop();
278 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700279 }
280
281 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700282 public void switchChanged(Dpid dpid) {
283 }
284
285 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700286 public void portChanged(Dpid dpid, OFPortStatus status) {
287 //TODO: Decide whether to evict flows internal store.
288 }
289
290 @Override
291 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabib902d41b2014-10-07 16:52:05 -0700292 InstallationFuture future = null;
alshabib8f1cf4a2014-09-17 14:44:48 -0700293 switch (msg.getType()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800294 case FLOW_REMOVED:
295 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700296
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800297 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
298 providerService.flowRemoved(fr);
299 break;
300 case STATS_REPLY:
301 pushFlowMetrics(dpid, (OFStatsReply) msg);
302 break;
303 case BARRIER_REPLY:
304 future = pendingFutures.get(msg.getXid());
305 if (future != null) {
306 future.satisfyRequirement(dpid);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800307 } else {
308 log.warn("Received unknown Barrier Reply: {}", msg.getXid());
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800309 }
310 break;
311 case ERROR:
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800312 log.warn("received Error message {} from {}", msg, dpid);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800313 future = pendingFMs.get(msg.getXid());
314 if (future != null) {
315 future.fail((OFErrorMsg) msg, dpid);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800316 } else {
317 log.warn("Received unknown Error Reply: {} {}", msg.getXid(), msg);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800318 }
319 break;
320 default:
321 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700322 }
323
324 }
325
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700326 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700327 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800328 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700329 // Do nothing here for now.
330 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700331
alshabib54ce5892014-09-23 17:50:51 -0700332 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib64def642014-12-02 23:27:37 -0800333
alshabib54ce5892014-09-23 17:50:51 -0700334 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700335 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700336
alshabib64def642014-12-02 23:27:37 -0800337 List<FlowEntry> flowEntries = replies.getEntries().stream()
338 .filter(entry -> !tableMissRule(dpid, entry))
339 .map(entry -> new FlowEntryBuilder(dpid, entry).build())
340 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700341
alshabib64def642014-12-02 23:27:37 -0800342 providerService.pushFlowMetrics(did, flowEntries);
343
alshabib5c370ff2014-09-18 10:12:14 -0700344 }
345
alshabib19fdc122014-10-03 11:38:19 -0700346 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
alshabib19fdc122014-10-03 11:38:19 -0700347 if (reply.getVersion().equals(OFVersion.OF_10) ||
348 reply.getMatch().getMatchFields().iterator().hasNext()) {
349 return false;
350 }
351 for (OFInstruction ins : reply.getInstructions()) {
352 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
353 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
354 List<OFAction> acts = apply.getActions();
355 for (OFAction act : acts) {
356 if (act.getType() == OFActionType.OUTPUT) {
357 OFActionOutput out = (OFActionOutput) act;
358 if (out.getPort() == OFPort.CONTROLLER) {
359 return true;
360 }
361 }
362 }
363 }
364 }
365 return false;
366 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700367
alshabib8f1cf4a2014-09-17 14:44:48 -0700368 }
alshabib1cc04f72014-09-16 16:09:58 -0700369
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800370 private class InstallationFuture implements Future<CompletedBatchOperation> {
alshabib902d41b2014-10-07 16:52:05 -0700371
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800372 // barrier xid
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800373 private final Long xid;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800374 // waiting for barrier reply from...
alshabib902d41b2014-10-07 16:52:05 -0700375 private final Set<Dpid> sws;
376 private final AtomicBoolean ok = new AtomicBoolean(true);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800377 // FlowMod xid ->
alshabib193525b2014-10-08 18:58:03 -0700378 private final Map<Long, FlowRuleBatchEntry> fms;
379
Brian O'Connor427a1762014-11-19 18:40:32 -0800380
Madan Jampani117aaae2014-10-23 10:04:05 -0700381 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800382 // Failed batch operation id
Brian O'Connor427a1762014-11-19 18:40:32 -0800383 private Long failedId;
alshabib902d41b2014-10-07 16:52:05 -0700384
385 private final CountDownLatch countDownLatch;
alshabib193525b2014-10-08 18:58:03 -0700386 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700387
alshabib193525b2014-10-08 18:58:03 -0700388 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800389 this.xid = xidCounter.getAndIncrement();
alshabib193525b2014-10-08 18:58:03 -0700390 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700391 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700392 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700393 countDownLatch = new CountDownLatch(sws.size());
394 }
395
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800396 public Long xid() {
397 return xid;
398 }
399
alshabib902d41b2014-10-07 16:52:05 -0700400 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700401
alshabib902d41b2014-10-07 16:52:05 -0700402 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700403 FlowEntry fe = null;
404 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
Brian O'Connor427a1762014-11-19 18:40:32 -0800405 failedId = fbe.id();
alshabib193525b2014-10-08 18:58:03 -0700406 FlowRule offending = fbe.getTarget();
alshabib902d41b2014-10-07 16:52:05 -0700407 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700408 switch (msg.getErrType()) {
409 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700410 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
411 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800412 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700413 break;
414 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700415 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
416 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800417 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700418 break;
419 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700420 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
421 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800422 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700423 break;
424 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700425 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
426 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800427 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700428 break;
429 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700430 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
431 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800432 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700433 break;
alshabib193525b2014-10-08 18:58:03 -0700434 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700435 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700436 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700437 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700438 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700439 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700440 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700441 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700442 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700443 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700444 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700445 break;
446 default:
alshabib193525b2014-10-08 18:58:03 -0700447 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700448
449 }
alshabib193525b2014-10-08 18:58:03 -0700450 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700451
Yuta HIGUCHI804a4bb2014-11-27 09:37:34 -0800452 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700453 }
454
alshabib193525b2014-10-08 18:58:03 -0700455
alshabib902d41b2014-10-07 16:52:05 -0700456 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700457 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700458 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700459 }
460
alshabib193525b2014-10-08 18:58:03 -0700461
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800462 public void verify() {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800463 checkState(!sws.isEmpty());
alshabib902d41b2014-10-07 16:52:05 -0700464 for (Dpid dpid : sws) {
465 OpenFlowSwitch sw = controller.getSwitch(dpid);
466 OFBarrierRequest.Builder builder = sw.factory()
467 .buildBarrierRequest()
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800468 .setXid(xid);
alshabib902d41b2014-10-07 16:52:05 -0700469 sw.sendMsg(builder.build());
470 }
alshabib902d41b2014-10-07 16:52:05 -0700471 }
472
473 @Override
474 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700475 if (isDone()) {
476 return false;
477 }
alshabib7911a052014-10-16 17:49:37 -0700478 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700479 this.state = BatchState.CANCELLED;
480 cleanUp();
481 for (FlowRuleBatchEntry fbe : fms.values()) {
482 if (fbe.getOperator() == FlowRuleOperation.ADD ||
483 fbe.getOperator() == FlowRuleOperation.MODIFY) {
484 removeFlowRule(fbe.getTarget());
485 } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
486 applyRule(fbe.getTarget());
487 }
488
489 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700490 return true;
alshabib902d41b2014-10-07 16:52:05 -0700491 }
492
493 @Override
494 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700495 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700496 }
497
498 @Override
499 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700500 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700501 }
502
503 @Override
alshabib193525b2014-10-08 18:58:03 -0700504 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700505 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700506 this.state = BatchState.FINISHED;
Brian O'Connor427a1762014-11-19 18:40:32 -0800507 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
508 CompletedBatchOperation result =
509 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
510 //FIXME do cleanup here (moved by BOC)
511 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700512 return result;
alshabib902d41b2014-10-07 16:52:05 -0700513 }
514
515 @Override
alshabib193525b2014-10-08 18:58:03 -0700516 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700517 throws InterruptedException, ExecutionException,
518 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700519 if (countDownLatch.await(timeout, unit)) {
520 this.state = BatchState.FINISHED;
Brian O'Connor427a1762014-11-19 18:40:32 -0800521 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
522 CompletedBatchOperation result =
523 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
524 // FIXME do cleanup here (moved by BOC)
525 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700526 return result;
alshabib26834582014-10-08 20:15:46 -0700527 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800528 throw new TimeoutException(this.toString());
alshabib193525b2014-10-08 18:58:03 -0700529 }
530
531 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700532 if (isDone() || isCancelled()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800533 pendingFutures.remove(xid);
alshabib193525b2014-10-08 18:58:03 -0700534 for (Long xid : fms.keySet()) {
535 pendingFMs.remove(xid);
536 }
537 }
alshabib902d41b2014-10-07 16:52:05 -0700538 }
539
alshabib7911a052014-10-16 17:49:37 -0700540 private void removeRequirement(Dpid dpid) {
541 countDownLatch.countDown();
542 sws.remove(dpid);
Brian O'Connor427a1762014-11-19 18:40:32 -0800543 //FIXME don't do cleanup here (moved by BOC)
544 //cleanUp();
alshabib7911a052014-10-16 17:49:37 -0700545 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800546
547 @Override
548 public String toString() {
549 return MoreObjects.toStringHelper(getClass())
550 .add("xid", xid)
551 .add("pending devices", sws)
552 .add("devices in batch",
553 fms.values().stream()
554 .map((fbe) -> fbe.getTarget().deviceId())
555 .distinct().collect(Collectors.toList()))
556 .add("failedId", failedId)
557 .add("latchCount", countDownLatch.getCount())
558 .add("state", state)
559 .add("no error?", ok.get())
560 .toString();
561 }
alshabib902d41b2014-10-07 16:52:05 -0700562 }
alshabiba68eb962014-09-24 20:34:13 -0700563
alshabib1cc04f72014-09-16 16:09:58 -0700564}