blob: 6a6249eae0b11b5fa60daebd1cad297cf49a2e15 [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
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;
Thomas Vachuskae0f804a2014-10-27 23:40:48 -070029import org.onlab.onos.core.ApplicationId;
alshabiba7f7ca82014-09-22 11:41:23 -070030import org.onlab.onos.net.DeviceId;
Jonathan Hart86e59352014-10-22 10:42:16 -070031import org.onlab.onos.net.flow.BatchOperation;
alshabib193525b2014-10-08 18:58:03 -070032import org.onlab.onos.net.flow.CompletedBatchOperation;
33import org.onlab.onos.net.flow.DefaultFlowEntry;
alshabib1c319ff2014-10-04 20:29:09 -070034import org.onlab.onos.net.flow.FlowEntry;
alshabib1cc04f72014-09-16 16:09:58 -070035import org.onlab.onos.net.flow.FlowRule;
alshabib902d41b2014-10-07 16:52:05 -070036import org.onlab.onos.net.flow.FlowRuleBatchEntry;
alshabib193525b2014-10-08 18:58:03 -070037import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
alshabib1cc04f72014-09-16 16:09:58 -070038import org.onlab.onos.net.flow.FlowRuleProvider;
39import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
40import org.onlab.onos.net.flow.FlowRuleProviderService;
41import org.onlab.onos.net.provider.AbstractProvider;
42import org.onlab.onos.net.provider.ProviderId;
43import org.onlab.onos.net.topology.TopologyService;
tom9c94c5b2014-09-17 13:14:42 -070044import org.onlab.onos.openflow.controller.Dpid;
45import org.onlab.onos.openflow.controller.OpenFlowController;
alshabibeec3a062014-09-17 18:01:26 -070046import org.onlab.onos.openflow.controller.OpenFlowEventListener;
tom9c94c5b2014-09-17 13:14:42 -070047import org.onlab.onos.openflow.controller.OpenFlowSwitch;
alshabibce4e5782014-09-17 14:56:42 -070048import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -070049import org.onlab.onos.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;
alshabib54ce5892014-09-23 17:50:51 -070061import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
alshabib5c370ff2014-09-18 10:12:14 -070062import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabib19fdc122014-10-03 11:38:19 -070063import org.projectfloodlight.openflow.protocol.OFVersion;
64import org.projectfloodlight.openflow.protocol.action.OFAction;
65import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
alshabib193525b2014-10-08 18:58:03 -070066import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
67import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
68import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
69import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
70import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib19fdc122014-10-03 11:38:19 -070071import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
72import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
73import org.projectfloodlight.openflow.types.OFPort;
alshabib1cc04f72014-09-16 16:09:58 -070074import org.slf4j.Logger;
75
Thomas Vachuska9b2da212014-11-10 19:30:25 -080076import java.util.Collections;
77import java.util.HashMap;
78import java.util.List;
79import java.util.Map;
Brian O'Connor427a1762014-11-19 18:40:32 -080080import java.util.Optional;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080081import java.util.Set;
82import java.util.concurrent.ConcurrentHashMap;
83import java.util.concurrent.CountDownLatch;
84import java.util.concurrent.ExecutionException;
85import java.util.concurrent.Future;
86import java.util.concurrent.TimeUnit;
87import java.util.concurrent.TimeoutException;
88import java.util.concurrent.atomic.AtomicBoolean;
89import java.util.concurrent.atomic.AtomicLong;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080090import java.util.stream.Collectors;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080091
Yuta HIGUCHI82e53262014-11-27 10:28:51 -080092import static com.google.common.base.Preconditions.checkState;
Thomas Vachuska9b2da212014-11-10 19:30:25 -080093import static org.slf4j.LoggerFactory.getLogger;
alshabibeec3a062014-09-17 18:01:26 -070094
alshabib1cc04f72014-09-16 16:09:58 -070095/**
96 * Provider which uses an OpenFlow controller to detect network
97 * end-station hosts.
98 */
99@Component(immediate = true)
100public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
101
alshabib193525b2014-10-08 18:58:03 -0700102 enum BatchState { STARTED, FINISHED, CANCELLED };
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.
alshabib902d41b2014-10-07 16:52:05 -0700121 private final Map<Long, InstallationFuture> pendingFutures =
122 new ConcurrentHashMap<Long, InstallationFuture>();
123
alshabib193525b2014-10-08 18:58:03 -0700124 private final Map<Long, InstallationFuture> pendingFMs =
125 new ConcurrentHashMap<Long, InstallationFuture>();
126
alshabib3d643ec2014-10-22 18:33:00 -0700127 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
128
Brian O'Connor427a1762014-11-19 18:40:32 -0800129 private final AtomicLong xidCounter = new AtomicLong(1);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800130
alshabib1cc04f72014-09-16 16:09:58 -0700131 /**
132 * Creates an OpenFlow host provider.
133 */
134 public OpenFlowRuleProvider() {
tom7e02cda2014-09-18 12:05:46 -0700135 super(new ProviderId("of", "org.onlab.onos.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700136 }
137
138 @Activate
139 public void activate() {
140 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700141 controller.addListener(listener);
142 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700143
144 for (OpenFlowSwitch sw : controller.getSwitches()) {
145 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
146 fsc.start();
147 collectors.put(new Dpid(sw.getId()), fsc);
148 }
149
150
alshabib1cc04f72014-09-16 16:09:58 -0700151 log.info("Started");
152 }
153
154 @Deactivate
155 public void deactivate() {
156 providerRegistry.unregister(this);
157 providerService = null;
158
159 log.info("Stopped");
160 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800161
alshabib1cc04f72014-09-16 16:09:58 -0700162 @Override
163 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -0700164 for (int i = 0; i < flowRules.length; i++) {
165 applyRule(flowRules[i]);
166 }
alshabib1cc04f72014-09-16 16:09:58 -0700167 }
168
alshabib35edb1a2014-09-16 17:44:44 -0700169 private void applyRule(FlowRule flowRule) {
170 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800171 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
172 Optional.empty()).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700173 }
174
alshabib35edb1a2014-09-16 17:44:44 -0700175
alshabib1cc04f72014-09-16 16:09:58 -0700176 @Override
177 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700178 for (int i = 0; i < flowRules.length; i++) {
179 removeRule(flowRules[i]);
180 }
alshabib1cc04f72014-09-16 16:09:58 -0700181
182 }
183
alshabib219ebaa2014-09-22 15:41:24 -0700184 private void removeRule(FlowRule flowRule) {
185 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800186 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
187 Optional.empty()).buildFlowDel());
alshabib219ebaa2014-09-22 15:41:24 -0700188 }
189
alshabiba68eb962014-09-24 20:34:13 -0700190 @Override
191 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
192 // TODO: optimize using the ApplicationId
193 removeFlowRule(flowRules);
194 }
195
alshabib193525b2014-10-08 18:58:03 -0700196 @Override
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800197 public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800198 final Set<Dpid> sws = Sets.newConcurrentHashSet();
199 final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>();
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800200 /*
201 * Use identity hash map for reference equality as we could have equal
202 * flow mods for different switches.
203 */
204 Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
alshabib193525b2014-10-08 18:58:03 -0700205 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
206 FlowRule flowRule = fbe.getTarget();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800207 final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
208 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib7911a052014-10-16 17:49:37 -0700209 if (sw == null) {
alshabib3effd042014-10-17 12:00:31 -0700210 /*
211 * if a switch we are supposed to install to is gone then
212 * cancel (ie. rollback) the work that has been done so far
213 * and return the associated future.
214 */
215 InstallationFuture failed = new InstallationFuture(sws, fmXids);
216 failed.cancel(true);
217 return failed;
alshabib7911a052014-10-16 17:49:37 -0700218 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800219 sws.add(dpid);
220 final Long flowModXid = xidCounter.getAndIncrement();
Brian O'Connor427a1762014-11-19 18:40:32 -0800221 FlowModBuilder builder =
222 FlowModBuilder.builder(flowRule, sw.factory(),
223 Optional.of(flowModXid));
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800224 OFFlowMod mod = null;
alshabib193525b2014-10-08 18:58:03 -0700225 switch (fbe.getOperator()) {
226 case ADD:
227 mod = builder.buildFlowAdd();
228 break;
229 case REMOVE:
230 mod = builder.buildFlowDel();
231 break;
232 case MODIFY:
233 mod = builder.buildFlowMod();
234 break;
235 default:
236 log.error("Unsupported batch operation {}", fbe.getOperator());
237 }
238 if (mod != null) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800239 mods.put(mod, sw);
Brian O'Connor427a1762014-11-19 18:40:32 -0800240 fmXids.put(flowModXid, fbe);
alshabib193525b2014-10-08 18:58:03 -0700241 } else {
242 log.error("Conversion of flowrule {} failed.", flowRule);
243 }
alshabib193525b2014-10-08 18:58:03 -0700244 }
245 InstallationFuture installation = new InstallationFuture(sws, fmXids);
246 for (Long xid : fmXids.keySet()) {
247 pendingFMs.put(xid, installation);
248 }
Brian O'Connor427a1762014-11-19 18:40:32 -0800249
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800250 pendingFutures.put(installation.xid(), installation);
251 for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
252 OpenFlowSwitch sw = entry.getValue();
253 OFFlowMod mod = entry.getKey();
254 sw.sendMsg(mod);
255 }
256 installation.verify();
alshabib193525b2014-10-08 18:58:03 -0700257 return installation;
258 }
259
260
alshabib8f1cf4a2014-09-17 14:44:48 -0700261 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800262 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700263
alshabib3d643ec2014-10-22 18:33:00 -0700264
alshabib1c319ff2014-10-04 20:29:09 -0700265 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700266 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700267
268 @Override
269 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700270 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700271 fsc.start();
272 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700273 }
274
275 @Override
276 public void switchRemoved(Dpid dpid) {
alshabibdfc7afb2014-10-21 20:13:27 -0700277 FlowStatsCollector collector = collectors.remove(dpid);
278 if (collector != null) {
279 collector.stop();
280 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700281 }
282
283 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700284 public void switchChanged(Dpid dpid) {
285 }
286
287 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700288 public void portChanged(Dpid dpid, OFPortStatus status) {
289 //TODO: Decide whether to evict flows internal store.
290 }
291
292 @Override
293 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabib902d41b2014-10-07 16:52:05 -0700294 InstallationFuture future = null;
alshabib8f1cf4a2014-09-17 14:44:48 -0700295 switch (msg.getType()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800296 case FLOW_REMOVED:
297 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700298
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800299 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
300 providerService.flowRemoved(fr);
301 break;
302 case STATS_REPLY:
303 pushFlowMetrics(dpid, (OFStatsReply) msg);
304 break;
305 case BARRIER_REPLY:
306 future = pendingFutures.get(msg.getXid());
307 if (future != null) {
308 future.satisfyRequirement(dpid);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800309 } else {
310 log.warn("Received unknown Barrier Reply: {}", msg.getXid());
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800311 }
312 break;
313 case ERROR:
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800314 log.warn("received Error message {} from {}", msg, dpid);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800315 future = pendingFMs.get(msg.getXid());
316 if (future != null) {
317 future.fail((OFErrorMsg) msg, dpid);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800318 } else {
319 log.warn("Received unknown Error Reply: {} {}", msg.getXid(), msg);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800320 }
321 break;
322 default:
323 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700324 }
325
326 }
327
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700328 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700329 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800330 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700331 // Do nothing here for now.
332 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700333
alshabib54ce5892014-09-23 17:50:51 -0700334 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib5c370ff2014-09-18 10:12:14 -0700335 if (stats.getStatsType() != OFStatsType.FLOW) {
336 return;
337 }
alshabib54ce5892014-09-23 17:50:51 -0700338 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700339 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700340 //final List<FlowRule> entries = Lists.newLinkedList();
341
alshabib5c370ff2014-09-18 10:12:14 -0700342 for (OFFlowStatsEntry reply : replies.getEntries()) {
alshabib19fdc122014-10-03 11:38:19 -0700343 if (!tableMissRule(dpid, reply)) {
alshabib1c319ff2014-10-04 20:29:09 -0700344 completeEntries.put(did, new FlowEntryBuilder(dpid, reply).build());
alshabib19fdc122014-10-03 11:38:19 -0700345 }
alshabib5c370ff2014-09-18 10:12:14 -0700346 }
alshabib54ce5892014-09-23 17:50:51 -0700347
348 if (!stats.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
Jonathan Hart58682dd2014-11-24 20:11:16 -0800349 log.trace("sending flowstats to core {}", completeEntries.get(did));
alshabib54ce5892014-09-23 17:50:51 -0700350 providerService.pushFlowMetrics(did, completeEntries.get(did));
351 completeEntries.removeAll(did);
352 }
alshabib5c370ff2014-09-18 10:12:14 -0700353 }
354
alshabib19fdc122014-10-03 11:38:19 -0700355 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
alshabib19fdc122014-10-03 11:38:19 -0700356 if (reply.getVersion().equals(OFVersion.OF_10) ||
357 reply.getMatch().getMatchFields().iterator().hasNext()) {
358 return false;
359 }
360 for (OFInstruction ins : reply.getInstructions()) {
361 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
362 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
363 List<OFAction> acts = apply.getActions();
364 for (OFAction act : acts) {
365 if (act.getType() == OFActionType.OUTPUT) {
366 OFActionOutput out = (OFActionOutput) act;
367 if (out.getPort() == OFPort.CONTROLLER) {
368 return true;
369 }
370 }
371 }
372 }
373 }
374 return false;
375 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700376
alshabib8f1cf4a2014-09-17 14:44:48 -0700377 }
alshabib1cc04f72014-09-16 16:09:58 -0700378
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800379 private class InstallationFuture implements Future<CompletedBatchOperation> {
alshabib902d41b2014-10-07 16:52:05 -0700380
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800381 // barrier xid
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800382 private final Long xid;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800383 // waiting for barrier reply from...
alshabib902d41b2014-10-07 16:52:05 -0700384 private final Set<Dpid> sws;
385 private final AtomicBoolean ok = new AtomicBoolean(true);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800386 // FlowMod xid ->
alshabib193525b2014-10-08 18:58:03 -0700387 private final Map<Long, FlowRuleBatchEntry> fms;
388
Brian O'Connor427a1762014-11-19 18:40:32 -0800389
Madan Jampani117aaae2014-10-23 10:04:05 -0700390 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800391 // Failed batch operation id
Brian O'Connor427a1762014-11-19 18:40:32 -0800392 private Long failedId;
alshabib902d41b2014-10-07 16:52:05 -0700393
394 private final CountDownLatch countDownLatch;
alshabib193525b2014-10-08 18:58:03 -0700395 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700396
alshabib193525b2014-10-08 18:58:03 -0700397 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800398 this.xid = xidCounter.getAndIncrement();
alshabib193525b2014-10-08 18:58:03 -0700399 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700400 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700401 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700402 countDownLatch = new CountDownLatch(sws.size());
403 }
404
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800405 public Long xid() {
406 return xid;
407 }
408
alshabib902d41b2014-10-07 16:52:05 -0700409 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700410
alshabib902d41b2014-10-07 16:52:05 -0700411 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700412 FlowEntry fe = null;
413 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
Brian O'Connor427a1762014-11-19 18:40:32 -0800414 failedId = fbe.id();
alshabib193525b2014-10-08 18:58:03 -0700415 FlowRule offending = fbe.getTarget();
alshabib902d41b2014-10-07 16:52:05 -0700416 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700417 switch (msg.getErrType()) {
418 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700419 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
420 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800421 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700422 break;
423 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700424 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
425 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800426 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700427 break;
428 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700429 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
430 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800431 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700432 break;
433 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700434 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
435 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800436 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700437 break;
438 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700439 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
440 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800441 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700442 break;
alshabib193525b2014-10-08 18:58:03 -0700443 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700444 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700445 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700446 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700447 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700448 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700449 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700450 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700451 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700452 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700453 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700454 break;
455 default:
alshabib193525b2014-10-08 18:58:03 -0700456 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700457
458 }
alshabib193525b2014-10-08 18:58:03 -0700459 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700460
Yuta HIGUCHI804a4bb2014-11-27 09:37:34 -0800461 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700462 }
463
alshabib193525b2014-10-08 18:58:03 -0700464
alshabib902d41b2014-10-07 16:52:05 -0700465 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700466 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700467 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700468 }
469
alshabib193525b2014-10-08 18:58:03 -0700470
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800471 public void verify() {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800472 checkState(!sws.isEmpty());
alshabib902d41b2014-10-07 16:52:05 -0700473 for (Dpid dpid : sws) {
474 OpenFlowSwitch sw = controller.getSwitch(dpid);
475 OFBarrierRequest.Builder builder = sw.factory()
476 .buildBarrierRequest()
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800477 .setXid(xid);
alshabib902d41b2014-10-07 16:52:05 -0700478 sw.sendMsg(builder.build());
479 }
alshabib902d41b2014-10-07 16:52:05 -0700480 }
481
482 @Override
483 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700484 if (isDone()) {
485 return false;
486 }
alshabib7911a052014-10-16 17:49:37 -0700487 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700488 this.state = BatchState.CANCELLED;
489 cleanUp();
490 for (FlowRuleBatchEntry fbe : fms.values()) {
491 if (fbe.getOperator() == FlowRuleOperation.ADD ||
492 fbe.getOperator() == FlowRuleOperation.MODIFY) {
493 removeFlowRule(fbe.getTarget());
494 } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
495 applyRule(fbe.getTarget());
496 }
497
498 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700499 return true;
alshabib902d41b2014-10-07 16:52:05 -0700500 }
501
502 @Override
503 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700504 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700505 }
506
507 @Override
508 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700509 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700510 }
511
512 @Override
alshabib193525b2014-10-08 18:58:03 -0700513 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700514 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700515 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;
alshabib902d41b2014-10-07 16:52:05 -0700522 }
523
524 @Override
alshabib193525b2014-10-08 18:58:03 -0700525 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700526 throws InterruptedException, ExecutionException,
527 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700528 if (countDownLatch.await(timeout, unit)) {
529 this.state = BatchState.FINISHED;
Brian O'Connor427a1762014-11-19 18:40:32 -0800530 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
531 CompletedBatchOperation result =
532 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
533 // FIXME do cleanup here (moved by BOC)
534 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700535 return result;
alshabib26834582014-10-08 20:15:46 -0700536 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800537 throw new TimeoutException(this.toString());
alshabib193525b2014-10-08 18:58:03 -0700538 }
539
540 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700541 if (isDone() || isCancelled()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800542 pendingFutures.remove(xid);
alshabib193525b2014-10-08 18:58:03 -0700543 for (Long xid : fms.keySet()) {
544 pendingFMs.remove(xid);
545 }
546 }
alshabib902d41b2014-10-07 16:52:05 -0700547 }
548
alshabib7911a052014-10-16 17:49:37 -0700549 private void removeRequirement(Dpid dpid) {
550 countDownLatch.countDown();
551 sws.remove(dpid);
Brian O'Connor427a1762014-11-19 18:40:32 -0800552 //FIXME don't do cleanup here (moved by BOC)
553 //cleanUp();
alshabib7911a052014-10-16 17:49:37 -0700554 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800555
556 @Override
557 public String toString() {
558 return MoreObjects.toStringHelper(getClass())
559 .add("xid", xid)
560 .add("pending devices", sws)
561 .add("devices in batch",
562 fms.values().stream()
563 .map((fbe) -> fbe.getTarget().deviceId())
564 .distinct().collect(Collectors.toList()))
565 .add("failedId", failedId)
566 .add("latchCount", countDownLatch.getCount())
567 .add("state", state)
568 .add("no error?", ok.get())
569 .toString();
570 }
alshabib902d41b2014-10-07 16:52:05 -0700571 }
alshabiba68eb962014-09-24 20:34:13 -0700572
alshabib1cc04f72014-09-16 16:09:58 -0700573}