blob: 32dfefdf12eb208c09bc0dbf67b54be1baf03082 [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
Jonathan Hart2ffcd102015-01-16 16:47:50 -080018import static com.google.common.base.Preconditions.checkState;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.util.Collections;
22import java.util.HashMap;
23import java.util.List;
24import java.util.Map;
25import java.util.Optional;
26import java.util.Set;
27import java.util.concurrent.ConcurrentHashMap;
28import java.util.concurrent.CountDownLatch;
29import java.util.concurrent.ExecutionException;
30import java.util.concurrent.Future;
31import java.util.concurrent.TimeUnit;
32import java.util.concurrent.TimeoutException;
33import java.util.concurrent.atomic.AtomicBoolean;
34import java.util.concurrent.atomic.AtomicLong;
35import java.util.stream.Collectors;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080036
alshabib1cc04f72014-09-16 16:09:58 -070037import org.apache.felix.scr.annotations.Activate;
38import org.apache.felix.scr.annotations.Component;
39import org.apache.felix.scr.annotations.Deactivate;
40import org.apache.felix.scr.annotations.Reference;
41import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.core.ApplicationId;
43import org.onosproject.net.DeviceId;
44import org.onosproject.net.flow.BatchOperation;
45import org.onosproject.net.flow.CompletedBatchOperation;
46import org.onosproject.net.flow.DefaultFlowEntry;
47import org.onosproject.net.flow.FlowEntry;
48import org.onosproject.net.flow.FlowRule;
49import org.onosproject.net.flow.FlowRuleBatchEntry;
50import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
51import org.onosproject.net.flow.FlowRuleProvider;
52import org.onosproject.net.flow.FlowRuleProviderRegistry;
53import org.onosproject.net.flow.FlowRuleProviderService;
54import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
56import org.onosproject.net.topology.TopologyService;
57import org.onosproject.openflow.controller.Dpid;
58import org.onosproject.openflow.controller.OpenFlowController;
59import org.onosproject.openflow.controller.OpenFlowEventListener;
60import org.onosproject.openflow.controller.OpenFlowSwitch;
61import org.onosproject.openflow.controller.OpenFlowSwitchListener;
62import org.onosproject.openflow.controller.RoleState;
alshabib19fdc122014-10-03 11:38:19 -070063import org.projectfloodlight.openflow.protocol.OFActionType;
alshabib902d41b2014-10-07 16:52:05 -070064import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
65import org.projectfloodlight.openflow.protocol.OFErrorMsg;
alshabib193525b2014-10-08 18:58:03 -070066import org.projectfloodlight.openflow.protocol.OFFlowMod;
alshabib8f1cf4a2014-09-17 14:44:48 -070067import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070068import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
69import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070070import org.projectfloodlight.openflow.protocol.OFInstructionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070071import org.projectfloodlight.openflow.protocol.OFMessage;
72import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070073import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070074import org.projectfloodlight.openflow.protocol.OFVersion;
75import org.projectfloodlight.openflow.protocol.action.OFAction;
76import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
alshabib193525b2014-10-08 18:58:03 -070077import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
78import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
79import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
80import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
81import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib19fdc122014-10-03 11:38:19 -070082import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
83import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
84import org.projectfloodlight.openflow.types.OFPort;
alshabib1cc04f72014-09-16 16:09:58 -070085import org.slf4j.Logger;
86
Jonathan Hart2ffcd102015-01-16 16:47:50 -080087import com.google.common.base.MoreObjects;
88import com.google.common.collect.ArrayListMultimap;
89import com.google.common.collect.Maps;
90import com.google.common.collect.Multimap;
91import com.google.common.collect.Sets;
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
Sho SHIMIZUfce9d4c2015-01-20 19:20:13 -0800100 enum BatchState { STARTED, FINISHED, CANCELLED }
alshabib193525b2014-10-08 18:58:03 -0700101
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800102 private static final int LOWEST_PRIORITY = 0;
103
alshabib1cc04f72014-09-16 16:09:58 -0700104 private final Logger log = getLogger(getClass());
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected FlowRuleProviderRegistry providerRegistry;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected OpenFlowController controller;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected TopologyService topologyService;
114
115 private FlowRuleProviderService providerService;
116
alshabibeec3a062014-09-17 18:01:26 -0700117 private final InternalFlowProvider listener = new InternalFlowProvider();
118
Madan Jampani117aaae2014-10-23 10:04:05 -0700119 // FIXME: This should be an expiring map to ensure futures that don't have
120 // a future eventually get garbage collected.
Sho SHIMIZU500c3172015-01-27 11:00:39 -0800121 private final Map<Long, InstallationFuture> pendingFutures = new ConcurrentHashMap<>();
alshabib902d41b2014-10-07 16:52:05 -0700122
Sho SHIMIZU500c3172015-01-27 11:00:39 -0800123 private final Map<Long, InstallationFuture> pendingFMs = new ConcurrentHashMap<>();
alshabib193525b2014-10-08 18:58:03 -0700124
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()) {
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800204 FlowRule flowRule = fbe.target();
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;
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800223 switch (fbe.operator()) {
alshabib193525b2014-10-08 18:58:03 -0700224 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:
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800234 log.error("Unsupported batch operation {}", fbe.operator());
alshabib193525b2014-10-08 18:58:03 -0700235 }
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
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800332 private 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) {
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800347 if (reply.getMatch().getMatchFields().iterator().hasNext()) {
alshabib19fdc122014-10-03 11:38:19 -0700348 return false;
349 }
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800350 if (reply.getVersion().equals(OFVersion.OF_10)) {
351 return reply.getPriority() == LOWEST_PRIORITY
352 && reply.getActions().isEmpty();
353 }
alshabib19fdc122014-10-03 11:38:19 -0700354 for (OFInstruction ins : reply.getInstructions()) {
355 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
356 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
357 List<OFAction> acts = apply.getActions();
358 for (OFAction act : acts) {
359 if (act.getType() == OFActionType.OUTPUT) {
360 OFActionOutput out = (OFActionOutput) act;
361 if (out.getPort() == OFPort.CONTROLLER) {
362 return true;
363 }
364 }
365 }
366 }
367 }
368 return false;
369 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700370
alshabib8f1cf4a2014-09-17 14:44:48 -0700371 }
alshabib1cc04f72014-09-16 16:09:58 -0700372
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800373 private class InstallationFuture implements Future<CompletedBatchOperation> {
alshabib902d41b2014-10-07 16:52:05 -0700374
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800375 // barrier xid
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800376 private final Long xid;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800377 // waiting for barrier reply from...
alshabib902d41b2014-10-07 16:52:05 -0700378 private final Set<Dpid> sws;
379 private final AtomicBoolean ok = new AtomicBoolean(true);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800380 // FlowMod xid ->
alshabib193525b2014-10-08 18:58:03 -0700381 private final Map<Long, FlowRuleBatchEntry> fms;
382
Brian O'Connor427a1762014-11-19 18:40:32 -0800383
Madan Jampani117aaae2014-10-23 10:04:05 -0700384 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800385 // Failed batch operation id
Sho SHIMIZUc0e8bfa2015-01-22 16:15:08 -0800386 private Long failedId;
alshabib902d41b2014-10-07 16:52:05 -0700387
388 private final CountDownLatch countDownLatch;
alshabib193525b2014-10-08 18:58:03 -0700389 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700390
alshabib193525b2014-10-08 18:58:03 -0700391 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800392 this.xid = xidCounter.getAndIncrement();
alshabib193525b2014-10-08 18:58:03 -0700393 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700394 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700395 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700396 countDownLatch = new CountDownLatch(sws.size());
397 }
398
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800399 public Long xid() {
400 return xid;
401 }
402
alshabib902d41b2014-10-07 16:52:05 -0700403 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700404
alshabib902d41b2014-10-07 16:52:05 -0700405 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700406 FlowEntry fe = null;
407 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
Brian O'Connor427a1762014-11-19 18:40:32 -0800408 failedId = fbe.id();
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800409 FlowRule offending = fbe.target();
alshabib902d41b2014-10-07 16:52:05 -0700410 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700411 switch (msg.getErrType()) {
412 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700413 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
414 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800415 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700416 break;
417 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700418 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
419 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800420 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700421 break;
422 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700423 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
424 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800425 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700426 break;
427 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700428 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
429 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800430 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700431 break;
432 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700433 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
434 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800435 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700436 break;
alshabib193525b2014-10-08 18:58:03 -0700437 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700438 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700439 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700440 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700441 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700442 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700443 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700444 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700445 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700446 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700447 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700448 break;
449 default:
alshabib193525b2014-10-08 18:58:03 -0700450 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700451
452 }
alshabib193525b2014-10-08 18:58:03 -0700453 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700454
Yuta HIGUCHI804a4bb2014-11-27 09:37:34 -0800455 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700456 }
457
alshabib193525b2014-10-08 18:58:03 -0700458
alshabib902d41b2014-10-07 16:52:05 -0700459 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700460 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700461 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700462 }
463
alshabib193525b2014-10-08 18:58:03 -0700464
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800465 public void verify() {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800466 checkState(!sws.isEmpty());
alshabib902d41b2014-10-07 16:52:05 -0700467 for (Dpid dpid : sws) {
468 OpenFlowSwitch sw = controller.getSwitch(dpid);
469 OFBarrierRequest.Builder builder = sw.factory()
470 .buildBarrierRequest()
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800471 .setXid(xid);
alshabib902d41b2014-10-07 16:52:05 -0700472 sw.sendMsg(builder.build());
473 }
alshabib902d41b2014-10-07 16:52:05 -0700474 }
475
476 @Override
477 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700478 if (isDone()) {
479 return false;
480 }
alshabib7911a052014-10-16 17:49:37 -0700481 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700482 this.state = BatchState.CANCELLED;
483 cleanUp();
484 for (FlowRuleBatchEntry fbe : fms.values()) {
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800485 if (fbe.operator() == FlowRuleOperation.ADD ||
486 fbe.operator() == FlowRuleOperation.MODIFY) {
487 removeFlowRule(fbe.target());
488 } else if (fbe.operator() == FlowRuleOperation.REMOVE) {
489 applyRule(fbe.target());
alshabib193525b2014-10-08 18:58:03 -0700490 }
491
492 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700493 return true;
alshabib902d41b2014-10-07 16:52:05 -0700494 }
495
496 @Override
497 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700498 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700499 }
500
501 @Override
502 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700503 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700504 }
505
506 @Override
alshabib193525b2014-10-08 18:58:03 -0700507 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700508 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700509 this.state = BatchState.FINISHED;
Sho SHIMIZUc0e8bfa2015-01-22 16:15:08 -0800510 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800511 CompletedBatchOperation result =
512 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
513 //FIXME do cleanup here (moved by BOC)
514 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700515 return result;
alshabib902d41b2014-10-07 16:52:05 -0700516 }
517
518 @Override
alshabib193525b2014-10-08 18:58:03 -0700519 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700520 throws InterruptedException, ExecutionException,
521 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700522 if (countDownLatch.await(timeout, unit)) {
523 this.state = BatchState.FINISHED;
Sho SHIMIZUc0e8bfa2015-01-22 16:15:08 -0800524 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800525 CompletedBatchOperation result =
526 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
527 // FIXME do cleanup here (moved by BOC)
528 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700529 return result;
alshabib26834582014-10-08 20:15:46 -0700530 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800531 throw new TimeoutException(this.toString());
alshabib193525b2014-10-08 18:58:03 -0700532 }
533
534 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700535 if (isDone() || isCancelled()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800536 pendingFutures.remove(xid);
alshabib193525b2014-10-08 18:58:03 -0700537 for (Long xid : fms.keySet()) {
538 pendingFMs.remove(xid);
539 }
540 }
alshabib902d41b2014-10-07 16:52:05 -0700541 }
542
alshabib7911a052014-10-16 17:49:37 -0700543 private void removeRequirement(Dpid dpid) {
544 countDownLatch.countDown();
545 sws.remove(dpid);
Brian O'Connor427a1762014-11-19 18:40:32 -0800546 //FIXME don't do cleanup here (moved by BOC)
547 //cleanUp();
alshabib7911a052014-10-16 17:49:37 -0700548 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800549
550 @Override
551 public String toString() {
552 return MoreObjects.toStringHelper(getClass())
553 .add("xid", xid)
554 .add("pending devices", sws)
555 .add("devices in batch",
556 fms.values().stream()
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800557 .map((fbe) -> fbe.target().deviceId())
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800558 .distinct().collect(Collectors.toList()))
559 .add("failedId", failedId)
560 .add("latchCount", countDownLatch.getCount())
561 .add("state", state)
562 .add("no error?", ok.get())
563 .toString();
564 }
alshabib902d41b2014-10-07 16:52:05 -0700565 }
alshabiba68eb962014-09-24 20:34:13 -0700566
alshabib1cc04f72014-09-16 16:09:58 -0700567}