blob: 7fbe09a327a00772b3dcd670c6fc8d6a6f2e24b2 [file] [log] [blame]
alshabib1cc04f72014-09-16 16:09:58 -07001package org.onlab.onos.provider.of.flow.impl;
2
Jonathan Hart11096402014-10-20 17:31:49 -07003import static org.slf4j.LoggerFactory.getLogger;
4
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
10import java.util.concurrent.ConcurrentHashMap;
11import java.util.concurrent.CountDownLatch;
12import java.util.concurrent.ExecutionException;
Madan Jampani117aaae2014-10-23 10:04:05 -070013import java.util.concurrent.Executor;
Jonathan Hart11096402014-10-20 17:31:49 -070014import java.util.concurrent.TimeUnit;
15import java.util.concurrent.TimeoutException;
16import java.util.concurrent.atomic.AtomicBoolean;
17
alshabib1cc04f72014-09-16 16:09:58 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabiba68eb962014-09-24 20:34:13 -070023import org.onlab.onos.ApplicationId;
alshabiba7f7ca82014-09-22 11:41:23 -070024import org.onlab.onos.net.DeviceId;
Jonathan Hart86e59352014-10-22 10:42:16 -070025import org.onlab.onos.net.flow.BatchOperation;
alshabib193525b2014-10-08 18:58:03 -070026import org.onlab.onos.net.flow.CompletedBatchOperation;
27import org.onlab.onos.net.flow.DefaultFlowEntry;
alshabib1c319ff2014-10-04 20:29:09 -070028import org.onlab.onos.net.flow.FlowEntry;
alshabib1cc04f72014-09-16 16:09:58 -070029import org.onlab.onos.net.flow.FlowRule;
alshabib902d41b2014-10-07 16:52:05 -070030import org.onlab.onos.net.flow.FlowRuleBatchEntry;
alshabib193525b2014-10-08 18:58:03 -070031import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
alshabib1cc04f72014-09-16 16:09:58 -070032import org.onlab.onos.net.flow.FlowRuleProvider;
33import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
34import org.onlab.onos.net.flow.FlowRuleProviderService;
35import org.onlab.onos.net.provider.AbstractProvider;
36import org.onlab.onos.net.provider.ProviderId;
37import org.onlab.onos.net.topology.TopologyService;
tom9c94c5b2014-09-17 13:14:42 -070038import org.onlab.onos.openflow.controller.Dpid;
39import org.onlab.onos.openflow.controller.OpenFlowController;
alshabibeec3a062014-09-17 18:01:26 -070040import org.onlab.onos.openflow.controller.OpenFlowEventListener;
tom9c94c5b2014-09-17 13:14:42 -070041import org.onlab.onos.openflow.controller.OpenFlowSwitch;
alshabibce4e5782014-09-17 14:56:42 -070042import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -070043import org.onlab.onos.openflow.controller.RoleState;
alshabib19fdc122014-10-03 11:38:19 -070044import org.projectfloodlight.openflow.protocol.OFActionType;
alshabib902d41b2014-10-07 16:52:05 -070045import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
46import org.projectfloodlight.openflow.protocol.OFErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070047import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070048import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070049import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
50import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070051import org.projectfloodlight.openflow.protocol.OFInstructionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070052import org.projectfloodlight.openflow.protocol.OFMessage;
53import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070054import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib54ce5892014-09-23 17:50:51 -070055import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
alshabib5c370ff2014-09-18 10:12:14 -070056import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabib19fdc122014-10-03 11:38:19 -070057import org.projectfloodlight.openflow.protocol.OFVersion;
58import org.projectfloodlight.openflow.protocol.action.OFAction;
59import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
alshabib193525b2014-10-08 18:58:03 -070060import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
61import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
62import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
63import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
64import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib19fdc122014-10-03 11:38:19 -070065import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
66import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
67import org.projectfloodlight.openflow.types.OFPort;
alshabib902d41b2014-10-07 16:52:05 -070068import org.projectfloodlight.openflow.types.U32;
alshabib1cc04f72014-09-16 16:09:58 -070069import org.slf4j.Logger;
70
Jonathan Hart11096402014-10-20 17:31:49 -070071import com.google.common.collect.ArrayListMultimap;
Jonathan Hart11096402014-10-20 17:31:49 -070072import com.google.common.collect.Maps;
73import com.google.common.collect.Multimap;
Madan Jampani117aaae2014-10-23 10:04:05 -070074import com.google.common.collect.Sets;
75import com.google.common.util.concurrent.ExecutionList;
76import com.google.common.util.concurrent.ListenableFuture;
alshabibeec3a062014-09-17 18:01:26 -070077
alshabib1cc04f72014-09-16 16:09:58 -070078/**
79 * Provider which uses an OpenFlow controller to detect network
80 * end-station hosts.
81 */
82@Component(immediate = true)
83public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
84
alshabib193525b2014-10-08 18:58:03 -070085 enum BatchState { STARTED, FINISHED, CANCELLED };
86
alshabib1cc04f72014-09-16 16:09:58 -070087 private final Logger log = getLogger(getClass());
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected FlowRuleProviderRegistry providerRegistry;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected OpenFlowController controller;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected TopologyService topologyService;
97
98 private FlowRuleProviderService providerService;
99
alshabibeec3a062014-09-17 18:01:26 -0700100 private final InternalFlowProvider listener = new InternalFlowProvider();
101
Madan Jampani117aaae2014-10-23 10:04:05 -0700102 // FIXME: This should be an expiring map to ensure futures that don't have
103 // a future eventually get garbage collected.
alshabib902d41b2014-10-07 16:52:05 -0700104 private final Map<Long, InstallationFuture> pendingFutures =
105 new ConcurrentHashMap<Long, InstallationFuture>();
106
alshabib193525b2014-10-08 18:58:03 -0700107 private final Map<Long, InstallationFuture> pendingFMs =
108 new ConcurrentHashMap<Long, InstallationFuture>();
109
alshabib3d643ec2014-10-22 18:33:00 -0700110 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
111
alshabib1cc04f72014-09-16 16:09:58 -0700112 /**
113 * Creates an OpenFlow host provider.
114 */
115 public OpenFlowRuleProvider() {
tom7e02cda2014-09-18 12:05:46 -0700116 super(new ProviderId("of", "org.onlab.onos.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700117 }
118
119 @Activate
120 public void activate() {
121 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700122 controller.addListener(listener);
123 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700124
125 for (OpenFlowSwitch sw : controller.getSwitches()) {
126 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
127 fsc.start();
128 collectors.put(new Dpid(sw.getId()), fsc);
129 }
130
131
alshabib1cc04f72014-09-16 16:09:58 -0700132 log.info("Started");
133 }
134
135 @Deactivate
136 public void deactivate() {
137 providerRegistry.unregister(this);
138 providerService = null;
139
140 log.info("Stopped");
141 }
142 @Override
143 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -0700144 for (int i = 0; i < flowRules.length; i++) {
145 applyRule(flowRules[i]);
146 }
alshabib1cc04f72014-09-16 16:09:58 -0700147 }
148
alshabib35edb1a2014-09-16 17:44:44 -0700149 private void applyRule(FlowRule flowRule) {
150 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Jonathan Hart86e59352014-10-22 10:42:16 -0700151 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory()).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700152 }
153
alshabib35edb1a2014-09-16 17:44:44 -0700154
alshabib35edb1a2014-09-16 17:44:44 -0700155
alshabib1cc04f72014-09-16 16:09:58 -0700156 @Override
157 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700158 for (int i = 0; i < flowRules.length; i++) {
159 removeRule(flowRules[i]);
160 }
alshabib1cc04f72014-09-16 16:09:58 -0700161
162 }
163
alshabib219ebaa2014-09-22 15:41:24 -0700164 private void removeRule(FlowRule flowRule) {
165 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Jonathan Hart86e59352014-10-22 10:42:16 -0700166 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory()).buildFlowDel());
alshabib219ebaa2014-09-22 15:41:24 -0700167 }
168
alshabiba68eb962014-09-24 20:34:13 -0700169 @Override
170 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
171 // TODO: optimize using the ApplicationId
172 removeFlowRule(flowRules);
173 }
174
alshabib193525b2014-10-08 18:58:03 -0700175 @Override
Madan Jampani117aaae2014-10-23 10:04:05 -0700176 public ListenableFuture<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
Jonathan Hart11096402014-10-20 17:31:49 -0700177 final Set<Dpid> sws =
178 Collections.newSetFromMap(new ConcurrentHashMap<Dpid, Boolean>());
alshabib193525b2014-10-08 18:58:03 -0700179 final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<Long, FlowRuleBatchEntry>();
180 OFFlowMod mod = null;
181 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
182 FlowRule flowRule = fbe.getTarget();
183 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
alshabib7911a052014-10-16 17:49:37 -0700184 if (sw == null) {
alshabib3effd042014-10-17 12:00:31 -0700185 /*
186 * if a switch we are supposed to install to is gone then
187 * cancel (ie. rollback) the work that has been done so far
188 * and return the associated future.
189 */
190 InstallationFuture failed = new InstallationFuture(sws, fmXids);
191 failed.cancel(true);
192 return failed;
alshabib7911a052014-10-16 17:49:37 -0700193 }
alshabib193525b2014-10-08 18:58:03 -0700194 sws.add(new Dpid(sw.getId()));
Jonathan Hart86e59352014-10-22 10:42:16 -0700195 FlowModBuilder builder = FlowModBuilder.builder(flowRule, sw.factory());
alshabib193525b2014-10-08 18:58:03 -0700196 switch (fbe.getOperator()) {
197 case ADD:
198 mod = builder.buildFlowAdd();
199 break;
200 case REMOVE:
201 mod = builder.buildFlowDel();
202 break;
203 case MODIFY:
204 mod = builder.buildFlowMod();
205 break;
206 default:
207 log.error("Unsupported batch operation {}", fbe.getOperator());
208 }
209 if (mod != null) {
210 sw.sendMsg(mod);
211 fmXids.put(mod.getXid(), fbe);
212 } else {
213 log.error("Conversion of flowrule {} failed.", flowRule);
214 }
alshabib219ebaa2014-09-22 15:41:24 -0700215
alshabib193525b2014-10-08 18:58:03 -0700216 }
217 InstallationFuture installation = new InstallationFuture(sws, fmXids);
218 for (Long xid : fmXids.keySet()) {
219 pendingFMs.put(xid, installation);
220 }
221 pendingFutures.put(U32.f(batch.hashCode()), installation);
alshabibdfc7afb2014-10-21 20:13:27 -0700222 installation.verify(U32.f(batch.hashCode()));
alshabib193525b2014-10-08 18:58:03 -0700223 return installation;
224 }
225
226
alshabib8f1cf4a2014-09-17 14:44:48 -0700227 private class InternalFlowProvider
228 implements OpenFlowSwitchListener, OpenFlowEventListener {
229
alshabib3d643ec2014-10-22 18:33:00 -0700230
alshabib1c319ff2014-10-04 20:29:09 -0700231 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700232 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700233
234 @Override
235 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700236 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700237 fsc.start();
238 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700239 }
240
241 @Override
242 public void switchRemoved(Dpid dpid) {
alshabibdfc7afb2014-10-21 20:13:27 -0700243 FlowStatsCollector collector = collectors.remove(dpid);
244 if (collector != null) {
245 collector.stop();
246 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700247 }
248
249 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700250 public void switchChanged(Dpid dpid) {
251 }
252
253 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700254 public void portChanged(Dpid dpid, OFPortStatus status) {
255 //TODO: Decide whether to evict flows internal store.
256 }
257
258 @Override
259 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabib902d41b2014-10-07 16:52:05 -0700260 InstallationFuture future = null;
alshabib8f1cf4a2014-09-17 14:44:48 -0700261 switch (msg.getType()) {
262 case FLOW_REMOVED:
263 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700264
alshabib1c319ff2014-10-04 20:29:09 -0700265 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
alshabib8f1cf4a2014-09-17 14:44:48 -0700266 providerService.flowRemoved(fr);
267 break;
268 case STATS_REPLY:
alshabib97044902014-09-18 14:52:16 -0700269 pushFlowMetrics(dpid, (OFStatsReply) msg);
alshabibeec3a062014-09-17 18:01:26 -0700270 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700271 case BARRIER_REPLY:
alshabib902d41b2014-10-07 16:52:05 -0700272 future = pendingFutures.get(msg.getXid());
273 if (future != null) {
274 future.satisfyRequirement(dpid);
275 }
276 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700277 case ERROR:
alshabib193525b2014-10-08 18:58:03 -0700278 future = pendingFMs.get(msg.getXid());
alshabib902d41b2014-10-07 16:52:05 -0700279 if (future != null) {
280 future.fail((OFErrorMsg) msg, dpid);
281 }
282 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700283 default:
alshabib6eb438a2014-10-01 16:39:37 -0700284 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700285 }
286
287 }
288
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700289 @Override
alshabib193525b2014-10-08 18:58:03 -0700290 public void roleAssertFailed(Dpid dpid, RoleState role) {}
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700291
alshabib54ce5892014-09-23 17:50:51 -0700292 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib5c370ff2014-09-18 10:12:14 -0700293 if (stats.getStatsType() != OFStatsType.FLOW) {
294 return;
295 }
alshabib54ce5892014-09-23 17:50:51 -0700296 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700297 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700298 //final List<FlowRule> entries = Lists.newLinkedList();
299
alshabib5c370ff2014-09-18 10:12:14 -0700300 for (OFFlowStatsEntry reply : replies.getEntries()) {
alshabib19fdc122014-10-03 11:38:19 -0700301 if (!tableMissRule(dpid, reply)) {
alshabib1c319ff2014-10-04 20:29:09 -0700302 completeEntries.put(did, new FlowEntryBuilder(dpid, reply).build());
alshabib19fdc122014-10-03 11:38:19 -0700303 }
alshabib5c370ff2014-09-18 10:12:14 -0700304 }
alshabib54ce5892014-09-23 17:50:51 -0700305
306 if (!stats.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
307 log.debug("sending flowstats to core {}", completeEntries.get(did));
308 providerService.pushFlowMetrics(did, completeEntries.get(did));
309 completeEntries.removeAll(did);
310 }
alshabib5c370ff2014-09-18 10:12:14 -0700311 }
312
alshabib19fdc122014-10-03 11:38:19 -0700313 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
alshabib19fdc122014-10-03 11:38:19 -0700314 if (reply.getVersion().equals(OFVersion.OF_10) ||
315 reply.getMatch().getMatchFields().iterator().hasNext()) {
316 return false;
317 }
318 for (OFInstruction ins : reply.getInstructions()) {
319 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
320 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
321 List<OFAction> acts = apply.getActions();
322 for (OFAction act : acts) {
323 if (act.getType() == OFActionType.OUTPUT) {
324 OFActionOutput out = (OFActionOutput) act;
325 if (out.getPort() == OFPort.CONTROLLER) {
326 return true;
327 }
328 }
329 }
330 }
331 }
332 return false;
333 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700334
alshabib8f1cf4a2014-09-17 14:44:48 -0700335 }
alshabib1cc04f72014-09-16 16:09:58 -0700336
Madan Jampani117aaae2014-10-23 10:04:05 -0700337 private class InstallationFuture implements ListenableFuture<CompletedBatchOperation> {
alshabib902d41b2014-10-07 16:52:05 -0700338
339 private final Set<Dpid> sws;
340 private final AtomicBoolean ok = new AtomicBoolean(true);
alshabib193525b2014-10-08 18:58:03 -0700341 private final Map<Long, FlowRuleBatchEntry> fms;
342
Madan Jampani117aaae2014-10-23 10:04:05 -0700343 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
alshabib902d41b2014-10-07 16:52:05 -0700344
345 private final CountDownLatch countDownLatch;
alshabibdfc7afb2014-10-21 20:13:27 -0700346 private Long pendingXid;
alshabib193525b2014-10-08 18:58:03 -0700347 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700348
Madan Jampani117aaae2014-10-23 10:04:05 -0700349 private final ExecutionList executionList = new ExecutionList();
350
alshabib193525b2014-10-08 18:58:03 -0700351 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
352 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700353 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700354 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700355 countDownLatch = new CountDownLatch(sws.size());
356 }
357
358 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700359
alshabib902d41b2014-10-07 16:52:05 -0700360 ok.set(false);
alshabib7911a052014-10-16 17:49:37 -0700361 removeRequirement(dpid);
alshabib193525b2014-10-08 18:58:03 -0700362 FlowEntry fe = null;
363 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
364 FlowRule offending = fbe.getTarget();
alshabib902d41b2014-10-07 16:52:05 -0700365 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700366 switch (msg.getErrType()) {
367 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700368 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
369 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
370 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700371 break;
372 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700373 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
374 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
375 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700376 break;
377 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700378 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
379 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
380 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700381 break;
382 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700383 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
384 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
385 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700386 break;
387 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700388 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
389 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
390 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700391 break;
alshabib193525b2014-10-08 18:58:03 -0700392 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700393 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700394 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700395 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700396 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700397 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700398 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700399 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700400 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700401 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700402 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700403 break;
404 default:
alshabib193525b2014-10-08 18:58:03 -0700405 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700406
407 }
alshabib193525b2014-10-08 18:58:03 -0700408 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700409
410 }
411
alshabib193525b2014-10-08 18:58:03 -0700412
alshabib902d41b2014-10-07 16:52:05 -0700413 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700414 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700415 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700416 }
417
alshabib193525b2014-10-08 18:58:03 -0700418
alshabibdfc7afb2014-10-21 20:13:27 -0700419 public void verify(Long id) {
alshabib193525b2014-10-08 18:58:03 -0700420 pendingXid = id;
alshabib902d41b2014-10-07 16:52:05 -0700421 for (Dpid dpid : sws) {
422 OpenFlowSwitch sw = controller.getSwitch(dpid);
423 OFBarrierRequest.Builder builder = sw.factory()
424 .buildBarrierRequest()
425 .setXid(id);
426 sw.sendMsg(builder.build());
427 }
alshabib902d41b2014-10-07 16:52:05 -0700428 }
429
430 @Override
431 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700432 if (isDone()) {
433 return false;
434 }
alshabib7911a052014-10-16 17:49:37 -0700435 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700436 this.state = BatchState.CANCELLED;
437 cleanUp();
438 for (FlowRuleBatchEntry fbe : fms.values()) {
439 if (fbe.getOperator() == FlowRuleOperation.ADD ||
440 fbe.getOperator() == FlowRuleOperation.MODIFY) {
441 removeFlowRule(fbe.getTarget());
442 } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
443 applyRule(fbe.getTarget());
444 }
445
446 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700447 invokeCallbacks();
448 return true;
alshabib902d41b2014-10-07 16:52:05 -0700449 }
450
451 @Override
452 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700453 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700454 }
455
456 @Override
457 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700458 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700459 }
460
461 @Override
alshabib193525b2014-10-08 18:58:03 -0700462 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700463 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700464 this.state = BatchState.FINISHED;
Madan Jampani117aaae2014-10-23 10:04:05 -0700465 CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods);
466 return result;
alshabib902d41b2014-10-07 16:52:05 -0700467 }
468
469 @Override
alshabib193525b2014-10-08 18:58:03 -0700470 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700471 throws InterruptedException, ExecutionException,
472 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700473 if (countDownLatch.await(timeout, unit)) {
474 this.state = BatchState.FINISHED;
Madan Jampani117aaae2014-10-23 10:04:05 -0700475 CompletedBatchOperation result = new CompletedBatchOperation(ok.get(), offendingFlowMods);
476 return result;
alshabib26834582014-10-08 20:15:46 -0700477 }
478 throw new TimeoutException();
alshabib193525b2014-10-08 18:58:03 -0700479 }
480
481 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700482 if (isDone() || isCancelled()) {
alshabibdfc7afb2014-10-21 20:13:27 -0700483 if (pendingXid != null) {
484 pendingFutures.remove(pendingXid);
485 }
alshabib193525b2014-10-08 18:58:03 -0700486 for (Long xid : fms.keySet()) {
487 pendingFMs.remove(xid);
488 }
489 }
alshabib902d41b2014-10-07 16:52:05 -0700490 }
491
alshabib7911a052014-10-16 17:49:37 -0700492 private void removeRequirement(Dpid dpid) {
493 countDownLatch.countDown();
Madan Jampani117aaae2014-10-23 10:04:05 -0700494 if (countDownLatch.getCount() == 0) {
495 invokeCallbacks();
496 }
alshabib7911a052014-10-16 17:49:37 -0700497 sws.remove(dpid);
498 cleanUp();
499 }
500
Madan Jampani117aaae2014-10-23 10:04:05 -0700501 @Override
502 public void addListener(Runnable runnable, Executor executor) {
503 executionList.add(runnable, executor);
504 }
505
506 private void invokeCallbacks() {
507 executionList.execute();
508 }
alshabib902d41b2014-10-07 16:52:05 -0700509 }
alshabiba68eb962014-09-24 20:34:13 -0700510
alshabib1cc04f72014-09-16 16:09:58 -0700511}