blob: 513dd0ccd397e13492ce302b13f2e0f074f07441 [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.
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() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800135 super(new ProviderId("of", "org.onosproject.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
Pavlin Radoslavov369c6432014-12-03 16:25:14 -0800334 private void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib64def642014-12-02 23:27:37 -0800335
alshabib54ce5892014-09-23 17:50:51 -0700336 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700337 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700338
alshabib64def642014-12-02 23:27:37 -0800339 List<FlowEntry> flowEntries = replies.getEntries().stream()
340 .filter(entry -> !tableMissRule(dpid, entry))
341 .map(entry -> new FlowEntryBuilder(dpid, entry).build())
342 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700343
alshabib64def642014-12-02 23:27:37 -0800344 providerService.pushFlowMetrics(did, flowEntries);
345
alshabib5c370ff2014-09-18 10:12:14 -0700346 }
347
alshabib19fdc122014-10-03 11:38:19 -0700348 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800349 if (reply.getMatch().getMatchFields().iterator().hasNext()) {
alshabib19fdc122014-10-03 11:38:19 -0700350 return false;
351 }
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800352 if (reply.getVersion().equals(OFVersion.OF_10)) {
353 return reply.getPriority() == LOWEST_PRIORITY
354 && reply.getActions().isEmpty();
355 }
alshabib19fdc122014-10-03 11:38:19 -0700356 for (OFInstruction ins : reply.getInstructions()) {
357 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
358 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
359 List<OFAction> acts = apply.getActions();
360 for (OFAction act : acts) {
361 if (act.getType() == OFActionType.OUTPUT) {
362 OFActionOutput out = (OFActionOutput) act;
363 if (out.getPort() == OFPort.CONTROLLER) {
364 return true;
365 }
366 }
367 }
368 }
369 }
370 return false;
371 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700372
alshabib8f1cf4a2014-09-17 14:44:48 -0700373 }
alshabib1cc04f72014-09-16 16:09:58 -0700374
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800375 private class InstallationFuture implements Future<CompletedBatchOperation> {
alshabib902d41b2014-10-07 16:52:05 -0700376
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800377 // barrier xid
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800378 private final Long xid;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800379 // waiting for barrier reply from...
alshabib902d41b2014-10-07 16:52:05 -0700380 private final Set<Dpid> sws;
381 private final AtomicBoolean ok = new AtomicBoolean(true);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800382 // FlowMod xid ->
alshabib193525b2014-10-08 18:58:03 -0700383 private final Map<Long, FlowRuleBatchEntry> fms;
384
Brian O'Connor427a1762014-11-19 18:40:32 -0800385
Madan Jampani117aaae2014-10-23 10:04:05 -0700386 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800387 // Failed batch operation id
Sho SHIMIZU9639df72015-01-21 13:38:43 -0800388 private Optional<Long> failedId;
alshabib902d41b2014-10-07 16:52:05 -0700389
390 private final CountDownLatch countDownLatch;
alshabib193525b2014-10-08 18:58:03 -0700391 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700392
alshabib193525b2014-10-08 18:58:03 -0700393 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800394 this.xid = xidCounter.getAndIncrement();
alshabib193525b2014-10-08 18:58:03 -0700395 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700396 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700397 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700398 countDownLatch = new CountDownLatch(sws.size());
399 }
400
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800401 public Long xid() {
402 return xid;
403 }
404
alshabib902d41b2014-10-07 16:52:05 -0700405 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700406
alshabib902d41b2014-10-07 16:52:05 -0700407 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700408 FlowEntry fe = null;
409 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
Brian O'Connor427a1762014-11-19 18:40:32 -0800410 failedId = fbe.id();
alshabib193525b2014-10-08 18:58:03 -0700411 FlowRule offending = fbe.getTarget();
alshabib902d41b2014-10-07 16:52:05 -0700412 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700413 switch (msg.getErrType()) {
414 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700415 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
416 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800417 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700418 break;
419 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700420 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
421 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800422 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700423 break;
424 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700425 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
426 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800427 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700428 break;
429 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700430 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
431 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800432 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700433 break;
434 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700435 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
436 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800437 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700438 break;
alshabib193525b2014-10-08 18:58:03 -0700439 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700440 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700441 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700442 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700443 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700444 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700445 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700446 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700447 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700448 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700449 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700450 break;
451 default:
alshabib193525b2014-10-08 18:58:03 -0700452 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700453
454 }
alshabib193525b2014-10-08 18:58:03 -0700455 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700456
Yuta HIGUCHI804a4bb2014-11-27 09:37:34 -0800457 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700458 }
459
alshabib193525b2014-10-08 18:58:03 -0700460
alshabib902d41b2014-10-07 16:52:05 -0700461 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700462 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700463 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700464 }
465
alshabib193525b2014-10-08 18:58:03 -0700466
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800467 public void verify() {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800468 checkState(!sws.isEmpty());
alshabib902d41b2014-10-07 16:52:05 -0700469 for (Dpid dpid : sws) {
470 OpenFlowSwitch sw = controller.getSwitch(dpid);
471 OFBarrierRequest.Builder builder = sw.factory()
472 .buildBarrierRequest()
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800473 .setXid(xid);
alshabib902d41b2014-10-07 16:52:05 -0700474 sw.sendMsg(builder.build());
475 }
alshabib902d41b2014-10-07 16:52:05 -0700476 }
477
478 @Override
479 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700480 if (isDone()) {
481 return false;
482 }
alshabib7911a052014-10-16 17:49:37 -0700483 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700484 this.state = BatchState.CANCELLED;
485 cleanUp();
486 for (FlowRuleBatchEntry fbe : fms.values()) {
487 if (fbe.getOperator() == FlowRuleOperation.ADD ||
488 fbe.getOperator() == FlowRuleOperation.MODIFY) {
489 removeFlowRule(fbe.getTarget());
490 } else if (fbe.getOperator() == FlowRuleOperation.REMOVE) {
491 applyRule(fbe.getTarget());
492 }
493
494 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700495 return true;
alshabib902d41b2014-10-07 16:52:05 -0700496 }
497
498 @Override
499 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700500 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700501 }
502
503 @Override
504 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700505 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700506 }
507
508 @Override
alshabib193525b2014-10-08 18:58:03 -0700509 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700510 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700511 this.state = BatchState.FINISHED;
Sho SHIMIZU9639df72015-01-21 13:38:43 -0800512 Set<Long> failedIds = (failedId.isPresent()) ? Sets.newHashSet(failedId.get()) : Collections.emptySet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800513 CompletedBatchOperation result =
514 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
515 //FIXME do cleanup here (moved by BOC)
516 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700517 return result;
alshabib902d41b2014-10-07 16:52:05 -0700518 }
519
520 @Override
alshabib193525b2014-10-08 18:58:03 -0700521 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700522 throws InterruptedException, ExecutionException,
523 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700524 if (countDownLatch.await(timeout, unit)) {
525 this.state = BatchState.FINISHED;
Sho SHIMIZU9639df72015-01-21 13:38:43 -0800526 Set<Long> failedIds = (failedId.isPresent()) ? Sets.newHashSet(failedId.get()) : Collections.emptySet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800527 CompletedBatchOperation result =
528 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
529 // FIXME do cleanup here (moved by BOC)
530 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700531 return result;
alshabib26834582014-10-08 20:15:46 -0700532 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800533 throw new TimeoutException(this.toString());
alshabib193525b2014-10-08 18:58:03 -0700534 }
535
536 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700537 if (isDone() || isCancelled()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800538 pendingFutures.remove(xid);
alshabib193525b2014-10-08 18:58:03 -0700539 for (Long xid : fms.keySet()) {
540 pendingFMs.remove(xid);
541 }
542 }
alshabib902d41b2014-10-07 16:52:05 -0700543 }
544
alshabib7911a052014-10-16 17:49:37 -0700545 private void removeRequirement(Dpid dpid) {
546 countDownLatch.countDown();
547 sws.remove(dpid);
Brian O'Connor427a1762014-11-19 18:40:32 -0800548 //FIXME don't do cleanup here (moved by BOC)
549 //cleanUp();
alshabib7911a052014-10-16 17:49:37 -0700550 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800551
552 @Override
553 public String toString() {
554 return MoreObjects.toStringHelper(getClass())
555 .add("xid", xid)
556 .add("pending devices", sws)
557 .add("devices in batch",
558 fms.values().stream()
559 .map((fbe) -> fbe.getTarget().deviceId())
560 .distinct().collect(Collectors.toList()))
561 .add("failedId", failedId)
562 .add("latchCount", countDownLatch.getCount())
563 .add("state", state)
564 .add("no error?", ok.get())
565 .toString();
566 }
alshabib902d41b2014-10-07 16:52:05 -0700567 }
alshabiba68eb962014-09-24 20:34:13 -0700568
alshabib1cc04f72014-09-16 16:09:58 -0700569}