blob: f09748e35394e39d807e86bb5d669d1c8c14cdaf [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 */
alshabib1cc04f72014-09-16 16:09:58 -070016package org.onlab.onos.provider.of.flow.impl;
17
Thomas Vachuska9b2da212014-11-10 19:30:25 -080018import com.google.common.collect.ArrayListMultimap;
19import com.google.common.collect.Maps;
20import com.google.common.collect.Multimap;
21import com.google.common.collect.Sets;
alshabib1cc04f72014-09-16 16:09:58 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuskae0f804a2014-10-27 23:40:48 -070027import org.onlab.onos.core.ApplicationId;
alshabiba7f7ca82014-09-22 11:41:23 -070028import org.onlab.onos.net.DeviceId;
Jonathan Hart86e59352014-10-22 10:42:16 -070029import org.onlab.onos.net.flow.BatchOperation;
alshabib193525b2014-10-08 18:58:03 -070030import org.onlab.onos.net.flow.CompletedBatchOperation;
31import org.onlab.onos.net.flow.DefaultFlowEntry;
alshabib1c319ff2014-10-04 20:29:09 -070032import org.onlab.onos.net.flow.FlowEntry;
alshabib1cc04f72014-09-16 16:09:58 -070033import org.onlab.onos.net.flow.FlowRule;
alshabib902d41b2014-10-07 16:52:05 -070034import org.onlab.onos.net.flow.FlowRuleBatchEntry;
alshabib193525b2014-10-08 18:58:03 -070035import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
alshabib1cc04f72014-09-16 16:09:58 -070036import org.onlab.onos.net.flow.FlowRuleProvider;
37import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
38import org.onlab.onos.net.flow.FlowRuleProviderService;
39import org.onlab.onos.net.provider.AbstractProvider;
40import org.onlab.onos.net.provider.ProviderId;
41import org.onlab.onos.net.topology.TopologyService;
tom9c94c5b2014-09-17 13:14:42 -070042import org.onlab.onos.openflow.controller.Dpid;
43import org.onlab.onos.openflow.controller.OpenFlowController;
alshabibeec3a062014-09-17 18:01:26 -070044import org.onlab.onos.openflow.controller.OpenFlowEventListener;
tom9c94c5b2014-09-17 13:14:42 -070045import org.onlab.onos.openflow.controller.OpenFlowSwitch;
alshabibce4e5782014-09-17 14:56:42 -070046import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -070047import org.onlab.onos.openflow.controller.RoleState;
alshabib19fdc122014-10-03 11:38:19 -070048import org.projectfloodlight.openflow.protocol.OFActionType;
alshabib902d41b2014-10-07 16:52:05 -070049import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
50import org.projectfloodlight.openflow.protocol.OFErrorMsg;
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.OFFlowStatsEntry;
54import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070055import org.projectfloodlight.openflow.protocol.OFInstructionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070056import org.projectfloodlight.openflow.protocol.OFMessage;
57import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070058import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib54ce5892014-09-23 17:50:51 -070059import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
alshabib5c370ff2014-09-18 10:12:14 -070060import org.projectfloodlight.openflow.protocol.OFStatsType;
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;
88
89import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070090
alshabib1cc04f72014-09-16 16:09:58 -070091/**
92 * Provider which uses an OpenFlow controller to detect network
93 * end-station hosts.
94 */
95@Component(immediate = true)
96public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
97
alshabib193525b2014-10-08 18:58:03 -070098 enum BatchState { STARTED, FINISHED, CANCELLED };
99
alshabib1cc04f72014-09-16 16:09:58 -0700100 private final Logger log = getLogger(getClass());
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected FlowRuleProviderRegistry providerRegistry;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected OpenFlowController controller;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected TopologyService topologyService;
110
111 private FlowRuleProviderService providerService;
112
alshabibeec3a062014-09-17 18:01:26 -0700113 private final InternalFlowProvider listener = new InternalFlowProvider();
114
Madan Jampani117aaae2014-10-23 10:04:05 -0700115 // FIXME: This should be an expiring map to ensure futures that don't have
116 // a future eventually get garbage collected.
alshabib902d41b2014-10-07 16:52:05 -0700117 private final Map<Long, InstallationFuture> pendingFutures =
118 new ConcurrentHashMap<Long, InstallationFuture>();
119
alshabib193525b2014-10-08 18:58:03 -0700120 private final Map<Long, InstallationFuture> pendingFMs =
121 new ConcurrentHashMap<Long, InstallationFuture>();
122
alshabib3d643ec2014-10-22 18:33:00 -0700123 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
124
Brian O'Connor427a1762014-11-19 18:40:32 -0800125 private final AtomicLong xidCounter = new AtomicLong(1);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800126
alshabib1cc04f72014-09-16 16:09:58 -0700127 /**
128 * Creates an OpenFlow host provider.
129 */
130 public OpenFlowRuleProvider() {
tom7e02cda2014-09-18 12:05:46 -0700131 super(new ProviderId("of", "org.onlab.onos.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700132 }
133
134 @Activate
135 public void activate() {
136 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700137 controller.addListener(listener);
138 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700139
140 for (OpenFlowSwitch sw : controller.getSwitches()) {
141 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
142 fsc.start();
143 collectors.put(new Dpid(sw.getId()), fsc);
144 }
145
146
alshabib1cc04f72014-09-16 16:09:58 -0700147 log.info("Started");
148 }
149
150 @Deactivate
151 public void deactivate() {
152 providerRegistry.unregister(this);
153 providerService = null;
154
155 log.info("Stopped");
156 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800157
alshabib1cc04f72014-09-16 16:09:58 -0700158 @Override
159 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -0700160 for (int i = 0; i < flowRules.length; i++) {
161 applyRule(flowRules[i]);
162 }
alshabib1cc04f72014-09-16 16:09:58 -0700163 }
164
alshabib35edb1a2014-09-16 17:44:44 -0700165 private void applyRule(FlowRule flowRule) {
166 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800167 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
168 Optional.empty()).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700169 }
170
alshabib35edb1a2014-09-16 17:44:44 -0700171
alshabib1cc04f72014-09-16 16:09:58 -0700172 @Override
173 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700174 for (int i = 0; i < flowRules.length; i++) {
175 removeRule(flowRules[i]);
176 }
alshabib1cc04f72014-09-16 16:09:58 -0700177
178 }
179
alshabib219ebaa2014-09-22 15:41:24 -0700180 private void removeRule(FlowRule flowRule) {
181 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800182 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
183 Optional.empty()).buildFlowDel());
alshabib219ebaa2014-09-22 15:41:24 -0700184 }
185
alshabiba68eb962014-09-24 20:34:13 -0700186 @Override
187 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
188 // TODO: optimize using the ApplicationId
189 removeFlowRule(flowRules);
190 }
191
alshabib193525b2014-10-08 18:58:03 -0700192 @Override
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800193 public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
Jonathan Hart11096402014-10-20 17:31:49 -0700194 final Set<Dpid> sws =
195 Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>());
alshabib193525b2014-10-08 18:58:03 -0700196 final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>();
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800197 /*
198 * Use identity hash map for reference equality as we could have equal
199 * flow mods for different switches.
200 */
201 Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
alshabib193525b2014-10-08 18:58:03 -0700202 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
203 FlowRule flowRule = fbe.getTarget();
204 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
alshabib7911a052014-10-16 17:49:37 -0700205 if (sw == null) {
alshabib3effd042014-10-17 12:00:31 -0700206 /*
207 * if a switch we are supposed to install to is gone then
208 * cancel (ie. rollback) the work that has been done so far
209 * and return the associated future.
210 */
211 InstallationFuture failed = new InstallationFuture(sws, fmXids);
212 failed.cancel(true);
213 return failed;
alshabib7911a052014-10-16 17:49:37 -0700214 }
alshabib193525b2014-10-08 18:58:03 -0700215 sws.add(new Dpid(sw.getId()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800216 Long flowModXid = xidCounter.getAndIncrement();
217 FlowModBuilder builder =
218 FlowModBuilder.builder(flowRule, sw.factory(),
219 Optional.of(flowModXid));
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800220 OFFlowMod mod = null;
alshabib193525b2014-10-08 18:58:03 -0700221 switch (fbe.getOperator()) {
222 case ADD:
223 mod = builder.buildFlowAdd();
224 break;
225 case REMOVE:
226 mod = builder.buildFlowDel();
227 break;
228 case MODIFY:
229 mod = builder.buildFlowMod();
230 break;
231 default:
232 log.error("Unsupported batch operation {}", fbe.getOperator());
233 }
234 if (mod != null) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800235 mods.put(mod, sw);
Brian O'Connor427a1762014-11-19 18:40:32 -0800236 fmXids.put(flowModXid, fbe);
alshabib193525b2014-10-08 18:58:03 -0700237 } else {
238 log.error("Conversion of flowrule {} failed.", flowRule);
239 }
alshabib193525b2014-10-08 18:58:03 -0700240 }
241 InstallationFuture installation = new InstallationFuture(sws, fmXids);
242 for (Long xid : fmXids.keySet()) {
243 pendingFMs.put(xid, installation);
244 }
Brian O'Connor427a1762014-11-19 18:40:32 -0800245
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800246 pendingFutures.put(installation.xid(), installation);
247 for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
248 OpenFlowSwitch sw = entry.getValue();
249 OFFlowMod mod = entry.getKey();
250 sw.sendMsg(mod);
251 }
252 installation.verify();
alshabib193525b2014-10-08 18:58:03 -0700253 return installation;
254 }
255
256
alshabib8f1cf4a2014-09-17 14:44:48 -0700257 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800258 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700259
alshabib3d643ec2014-10-22 18:33:00 -0700260
alshabib1c319ff2014-10-04 20:29:09 -0700261 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700262 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700263
264 @Override
265 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700266 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700267 fsc.start();
268 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700269 }
270
271 @Override
272 public void switchRemoved(Dpid dpid) {
alshabibdfc7afb2014-10-21 20:13:27 -0700273 FlowStatsCollector collector = collectors.remove(dpid);
274 if (collector != null) {
275 collector.stop();
276 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700277 }
278
279 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700280 public void switchChanged(Dpid dpid) {
281 }
282
283 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700284 public void portChanged(Dpid dpid, OFPortStatus status) {
285 //TODO: Decide whether to evict flows internal store.
286 }
287
288 @Override
289 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabib902d41b2014-10-07 16:52:05 -0700290 InstallationFuture future = null;
alshabib8f1cf4a2014-09-17 14:44:48 -0700291 switch (msg.getType()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800292 case FLOW_REMOVED:
293 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700294
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800295 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
296 providerService.flowRemoved(fr);
297 break;
298 case STATS_REPLY:
299 pushFlowMetrics(dpid, (OFStatsReply) msg);
300 break;
301 case BARRIER_REPLY:
302 future = pendingFutures.get(msg.getXid());
303 if (future != null) {
304 future.satisfyRequirement(dpid);
305 }
306 break;
307 case ERROR:
308 future = pendingFMs.get(msg.getXid());
309 if (future != null) {
310 future.fail((OFErrorMsg) msg, dpid);
311 }
312 break;
313 default:
314 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700315 }
316
317 }
318
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700319 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700320 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800321 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700322 // Do nothing here for now.
323 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700324
alshabib54ce5892014-09-23 17:50:51 -0700325 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib5c370ff2014-09-18 10:12:14 -0700326 if (stats.getStatsType() != OFStatsType.FLOW) {
327 return;
328 }
alshabib54ce5892014-09-23 17:50:51 -0700329 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700330 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700331 //final List<FlowRule> entries = Lists.newLinkedList();
332
alshabib5c370ff2014-09-18 10:12:14 -0700333 for (OFFlowStatsEntry reply : replies.getEntries()) {
alshabib19fdc122014-10-03 11:38:19 -0700334 if (!tableMissRule(dpid, reply)) {
alshabib1c319ff2014-10-04 20:29:09 -0700335 completeEntries.put(did, new FlowEntryBuilder(dpid, reply).build());
alshabib19fdc122014-10-03 11:38:19 -0700336 }
alshabib5c370ff2014-09-18 10:12:14 -0700337 }
alshabib54ce5892014-09-23 17:50:51 -0700338
339 if (!stats.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
340 log.debug("sending flowstats to core {}", completeEntries.get(did));
341 providerService.pushFlowMetrics(did, completeEntries.get(did));
342 completeEntries.removeAll(did);
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
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800372 private final Long xid;
alshabib902d41b2014-10-07 16:52:05 -0700373 private final Set<Dpid> sws;
374 private final AtomicBoolean ok = new AtomicBoolean(true);
alshabib193525b2014-10-08 18:58:03 -0700375 private final Map<Long, FlowRuleBatchEntry> fms;
376
Brian O'Connor427a1762014-11-19 18:40:32 -0800377
Madan Jampani117aaae2014-10-23 10:04:05 -0700378 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800379 private Long failedId;
alshabib902d41b2014-10-07 16:52:05 -0700380
381 private final CountDownLatch countDownLatch;
alshabib193525b2014-10-08 18:58:03 -0700382 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700383
alshabib193525b2014-10-08 18:58:03 -0700384 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800385 this.xid = xidCounter.getAndIncrement();
alshabib193525b2014-10-08 18:58:03 -0700386 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700387 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700388 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700389 countDownLatch = new CountDownLatch(sws.size());
390 }
391
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800392 public Long xid() {
393 return xid;
394 }
395
alshabib902d41b2014-10-07 16:52:05 -0700396 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700397
alshabib902d41b2014-10-07 16:52:05 -0700398 ok.set(false);
alshabib7911a052014-10-16 17:49:37 -0700399 removeRequirement(dpid);
alshabib193525b2014-10-08 18:58:03 -0700400 FlowEntry fe = null;
401 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
Brian O'Connor427a1762014-11-19 18:40:32 -0800402 failedId = fbe.id();
alshabib193525b2014-10-08 18:58:03 -0700403 FlowRule offending = fbe.getTarget();
alshabib902d41b2014-10-07 16:52:05 -0700404 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700405 switch (msg.getErrType()) {
406 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700407 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
408 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800409 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700410 break;
411 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700412 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
413 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800414 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700415 break;
416 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700417 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
418 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800419 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700420 break;
421 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700422 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
423 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800424 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700425 break;
426 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700427 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
428 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800429 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700430 break;
alshabib193525b2014-10-08 18:58:03 -0700431 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700432 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700433 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700434 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700435 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700436 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700437 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700438 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700439 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700440 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700441 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700442 break;
443 default:
alshabib193525b2014-10-08 18:58:03 -0700444 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700445
446 }
alshabib193525b2014-10-08 18:58:03 -0700447 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700448
449 }
450
alshabib193525b2014-10-08 18:58:03 -0700451
alshabib902d41b2014-10-07 16:52:05 -0700452 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700453 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700454 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700455 }
456
alshabib193525b2014-10-08 18:58:03 -0700457
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800458 public void verify() {
alshabib902d41b2014-10-07 16:52:05 -0700459 for (Dpid dpid : sws) {
460 OpenFlowSwitch sw = controller.getSwitch(dpid);
461 OFBarrierRequest.Builder builder = sw.factory()
462 .buildBarrierRequest()
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800463 .setXid(xid);
alshabib902d41b2014-10-07 16:52:05 -0700464 sw.sendMsg(builder.build());
465 }
alshabib902d41b2014-10-07 16:52:05 -0700466 }
467
468 @Override
469 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700470 if (isDone()) {
471 return false;
472 }
alshabib7911a052014-10-16 17:49:37 -0700473 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700474 this.state = BatchState.CANCELLED;
475 cleanUp();
476 for (FlowRuleBatchEntry fbe : fms.values()) {
477 if (fbe.getOperator() == FlowRuleOperation.ADD ||
478 fbe.getOperator() == FlowRuleOperation.MODIFY) {
479 removeFlowRule(fbe.getTarget());
480 } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
481 applyRule(fbe.getTarget());
482 }
483
484 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700485 return true;
alshabib902d41b2014-10-07 16:52:05 -0700486 }
487
488 @Override
489 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700490 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700491 }
492
493 @Override
494 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700495 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700496 }
497
498 @Override
alshabib193525b2014-10-08 18:58:03 -0700499 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700500 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700501 this.state = BatchState.FINISHED;
Brian O'Connor427a1762014-11-19 18:40:32 -0800502 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
503 CompletedBatchOperation result =
504 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
505 //FIXME do cleanup here (moved by BOC)
506 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700507 return result;
alshabib902d41b2014-10-07 16:52:05 -0700508 }
509
510 @Override
alshabib193525b2014-10-08 18:58:03 -0700511 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700512 throws InterruptedException, ExecutionException,
513 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700514 if (countDownLatch.await(timeout, unit)) {
515 this.state = BatchState.FINISHED;
Brian O'Connor427a1762014-11-19 18:40:32 -0800516 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
517 CompletedBatchOperation result =
518 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
519 // FIXME do cleanup here (moved by BOC)
520 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700521 return result;
alshabib26834582014-10-08 20:15:46 -0700522 }
523 throw new TimeoutException();
alshabib193525b2014-10-08 18:58:03 -0700524 }
525
526 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700527 if (isDone() || isCancelled()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800528 pendingFutures.remove(xid);
alshabib193525b2014-10-08 18:58:03 -0700529 for (Long xid : fms.keySet()) {
530 pendingFMs.remove(xid);
531 }
532 }
alshabib902d41b2014-10-07 16:52:05 -0700533 }
534
alshabib7911a052014-10-16 17:49:37 -0700535 private void removeRequirement(Dpid dpid) {
536 countDownLatch.countDown();
537 sws.remove(dpid);
Brian O'Connor427a1762014-11-19 18:40:32 -0800538 //FIXME don't do cleanup here (moved by BOC)
539 //cleanUp();
alshabib7911a052014-10-16 17:49:37 -0700540 }
alshabib902d41b2014-10-07 16:52:05 -0700541 }
alshabiba68eb962014-09-24 20:34:13 -0700542
alshabib1cc04f72014-09-16 16:09:58 -0700543}