blob: dd0bcaa53d77c74fa74dfa180316e0a311677b48 [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;
sangho89bf6fb2015-02-09 09:33:13 -080074import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabib19fdc122014-10-03 11:38:19 -070075import org.projectfloodlight.openflow.protocol.OFVersion;
76import org.projectfloodlight.openflow.protocol.action.OFAction;
77import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
alshabib193525b2014-10-08 18:58:03 -070078import org.projectfloodlight.openflow.protocol.errormsg.OFBadActionErrorMsg;
79import org.projectfloodlight.openflow.protocol.errormsg.OFBadInstructionErrorMsg;
80import org.projectfloodlight.openflow.protocol.errormsg.OFBadMatchErrorMsg;
81import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
82import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
alshabib19fdc122014-10-03 11:38:19 -070083import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
84import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
85import org.projectfloodlight.openflow.types.OFPort;
alshabib1cc04f72014-09-16 16:09:58 -070086import org.slf4j.Logger;
87
Jonathan Hart2ffcd102015-01-16 16:47:50 -080088import com.google.common.base.MoreObjects;
89import com.google.common.collect.ArrayListMultimap;
90import com.google.common.collect.Maps;
91import com.google.common.collect.Multimap;
92import com.google.common.collect.Sets;
alshabibeec3a062014-09-17 18:01:26 -070093
alshabib1cc04f72014-09-16 16:09:58 -070094/**
95 * Provider which uses an OpenFlow controller to detect network
96 * end-station hosts.
97 */
98@Component(immediate = true)
99public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
100
Sho SHIMIZUfce9d4c2015-01-20 19:20:13 -0800101 enum BatchState { STARTED, FINISHED, CANCELLED }
alshabib193525b2014-10-08 18:58:03 -0700102
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800103 private static final int LOWEST_PRIORITY = 0;
104
alshabib1cc04f72014-09-16 16:09:58 -0700105 private final Logger log = getLogger(getClass());
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected FlowRuleProviderRegistry providerRegistry;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected OpenFlowController controller;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected TopologyService topologyService;
115
116 private FlowRuleProviderService providerService;
117
alshabibeec3a062014-09-17 18:01:26 -0700118 private final InternalFlowProvider listener = new InternalFlowProvider();
119
Madan Jampani117aaae2014-10-23 10:04:05 -0700120 // FIXME: This should be an expiring map to ensure futures that don't have
121 // a future eventually get garbage collected.
Sho SHIMIZU500c3172015-01-27 11:00:39 -0800122 private final Map<Long, InstallationFuture> pendingFutures = new ConcurrentHashMap<>();
alshabib902d41b2014-10-07 16:52:05 -0700123
Sho SHIMIZU500c3172015-01-27 11:00:39 -0800124 private final Map<Long, InstallationFuture> pendingFMs = new ConcurrentHashMap<>();
alshabib193525b2014-10-08 18:58:03 -0700125
alshabib3d643ec2014-10-22 18:33:00 -0700126 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
127
Brian O'Connor427a1762014-11-19 18:40:32 -0800128 private final AtomicLong xidCounter = new AtomicLong(1);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800129
alshabib1cc04f72014-09-16 16:09:58 -0700130 /**
131 * Creates an OpenFlow host provider.
132 */
133 public OpenFlowRuleProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800134 super(new ProviderId("of", "org.onosproject.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -0700135 }
136
137 @Activate
138 public void activate() {
139 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700140 controller.addListener(listener);
141 controller.addEventListener(listener);
alshabib3d643ec2014-10-22 18:33:00 -0700142
143 for (OpenFlowSwitch sw : controller.getSwitches()) {
144 FlowStatsCollector fsc = new FlowStatsCollector(sw, POLL_INTERVAL);
145 fsc.start();
146 collectors.put(new Dpid(sw.getId()), fsc);
147 }
148
149
alshabib1cc04f72014-09-16 16:09:58 -0700150 log.info("Started");
151 }
152
153 @Deactivate
154 public void deactivate() {
155 providerRegistry.unregister(this);
156 providerService = null;
157
158 log.info("Stopped");
159 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800160
alshabib1cc04f72014-09-16 16:09:58 -0700161 @Override
162 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -0700163 for (int i = 0; i < flowRules.length; i++) {
164 applyRule(flowRules[i]);
165 }
alshabib1cc04f72014-09-16 16:09:58 -0700166 }
167
alshabib35edb1a2014-09-16 17:44:44 -0700168 private void applyRule(FlowRule flowRule) {
169 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
sangho87af8112015-01-29 12:53:08 -0800170 if (flowRule.type() == FlowRule.Type.DEFAULT) {
171 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
172 Optional.empty()).buildFlowAdd());
173 } else {
174 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
175 Optional.empty()).buildFlowAdd(), getTableType(flowRule.type()));
176 }
alshabib35edb1a2014-09-16 17:44:44 -0700177 }
178
alshabib35edb1a2014-09-16 17:44:44 -0700179
alshabib1cc04f72014-09-16 16:09:58 -0700180 @Override
181 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700182 for (int i = 0; i < flowRules.length; i++) {
183 removeRule(flowRules[i]);
184 }
alshabib1cc04f72014-09-16 16:09:58 -0700185
186 }
187
alshabib219ebaa2014-09-22 15:41:24 -0700188 private void removeRule(FlowRule flowRule) {
189 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
sangho87af8112015-01-29 12:53:08 -0800190 if (flowRule.type() == FlowRule.Type.DEFAULT) {
191 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
192 Optional.empty()).buildFlowDel());
193 } else {
194 sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
195 Optional.empty()).buildFlowDel(), getTableType(flowRule.type()));
196 }
alshabib219ebaa2014-09-22 15:41:24 -0700197 }
198
alshabiba68eb962014-09-24 20:34:13 -0700199 @Override
200 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
201 // TODO: optimize using the ApplicationId
202 removeFlowRule(flowRules);
203 }
204
alshabib193525b2014-10-08 18:58:03 -0700205 @Override
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800206 public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800207 final Set<Dpid> sws = Sets.newConcurrentHashSet();
208 final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>();
sangho87af8112015-01-29 12:53:08 -0800209
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800210 /*
211 * Use identity hash map for reference equality as we could have equal
212 * flow mods for different switches.
213 */
214 Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
sangho87af8112015-01-29 12:53:08 -0800215 Map<OFFlowMod, OpenFlowSwitch.TableType> modTypes = Maps.newIdentityHashMap();
alshabib193525b2014-10-08 18:58:03 -0700216 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800217 FlowRule flowRule = fbe.target();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800218 final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri());
219 OpenFlowSwitch sw = controller.getSwitch(dpid);
alshabib7911a052014-10-16 17:49:37 -0700220 if (sw == null) {
alshabib3effd042014-10-17 12:00:31 -0700221 /*
222 * if a switch we are supposed to install to is gone then
223 * cancel (ie. rollback) the work that has been done so far
224 * and return the associated future.
225 */
226 InstallationFuture failed = new InstallationFuture(sws, fmXids);
227 failed.cancel(true);
228 return failed;
alshabib7911a052014-10-16 17:49:37 -0700229 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800230 sws.add(dpid);
231 final Long flowModXid = xidCounter.getAndIncrement();
Brian O'Connor427a1762014-11-19 18:40:32 -0800232 FlowModBuilder builder =
233 FlowModBuilder.builder(flowRule, sw.factory(),
234 Optional.of(flowModXid));
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800235 OFFlowMod mod = null;
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800236 switch (fbe.operator()) {
alshabib193525b2014-10-08 18:58:03 -0700237 case ADD:
238 mod = builder.buildFlowAdd();
239 break;
240 case REMOVE:
241 mod = builder.buildFlowDel();
242 break;
243 case MODIFY:
244 mod = builder.buildFlowMod();
245 break;
246 default:
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800247 log.error("Unsupported batch operation {}", fbe.operator());
alshabib193525b2014-10-08 18:58:03 -0700248 }
249 if (mod != null) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800250 mods.put(mod, sw);
sangho87af8112015-01-29 12:53:08 -0800251 modTypes.put(mod, getTableType(flowRule.type()));
Brian O'Connor427a1762014-11-19 18:40:32 -0800252 fmXids.put(flowModXid, fbe);
alshabib193525b2014-10-08 18:58:03 -0700253 } else {
254 log.error("Conversion of flowrule {} failed.", flowRule);
255 }
alshabib193525b2014-10-08 18:58:03 -0700256 }
257 InstallationFuture installation = new InstallationFuture(sws, fmXids);
258 for (Long xid : fmXids.keySet()) {
259 pendingFMs.put(xid, installation);
260 }
Brian O'Connor427a1762014-11-19 18:40:32 -0800261
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800262 pendingFutures.put(installation.xid(), installation);
263 for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) {
264 OpenFlowSwitch sw = entry.getValue();
265 OFFlowMod mod = entry.getKey();
sangho87af8112015-01-29 12:53:08 -0800266 OpenFlowSwitch.TableType tableType = modTypes.get(mod);
267 if (tableType == OpenFlowSwitch.TableType.NONE) {
268 sw.sendMsg(mod);
269 } else {
270 sw.sendMsg(mod, tableType);
271 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800272 }
273 installation.verify();
alshabib193525b2014-10-08 18:58:03 -0700274 return installation;
275 }
276
sangho87af8112015-01-29 12:53:08 -0800277 private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) {
278 switch (type) {
279 case IP:
280 return OpenFlowSwitch.TableType.IP;
281 case MPLS:
282 return OpenFlowSwitch.TableType.MPLS;
283 case ACL:
284 return OpenFlowSwitch.TableType.ACL;
285 default:
286 return OpenFlowSwitch.TableType.NONE;
287 }
288 }
alshabib193525b2014-10-08 18:58:03 -0700289
alshabib8f1cf4a2014-09-17 14:44:48 -0700290 private class InternalFlowProvider
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800291 implements OpenFlowSwitchListener, OpenFlowEventListener {
alshabib8f1cf4a2014-09-17 14:44:48 -0700292
alshabib3d643ec2014-10-22 18:33:00 -0700293
alshabib1c319ff2014-10-04 20:29:09 -0700294 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700295 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700296
297 @Override
298 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700299 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700300 fsc.start();
301 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700302 }
303
304 @Override
305 public void switchRemoved(Dpid dpid) {
alshabibdfc7afb2014-10-21 20:13:27 -0700306 FlowStatsCollector collector = collectors.remove(dpid);
307 if (collector != null) {
308 collector.stop();
309 }
alshabib8f1cf4a2014-09-17 14:44:48 -0700310 }
311
312 @Override
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700313 public void switchChanged(Dpid dpid) {
314 }
315
316 @Override
alshabib8f1cf4a2014-09-17 14:44:48 -0700317 public void portChanged(Dpid dpid, OFPortStatus status) {
318 //TODO: Decide whether to evict flows internal store.
319 }
320
321 @Override
322 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabib902d41b2014-10-07 16:52:05 -0700323 InstallationFuture future = null;
alshabib8f1cf4a2014-09-17 14:44:48 -0700324 switch (msg.getType()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800325 case FLOW_REMOVED:
326 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700327
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800328 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
329 providerService.flowRemoved(fr);
330 break;
331 case STATS_REPLY:
sangho89bf6fb2015-02-09 09:33:13 -0800332 if (((OFStatsReply) msg).getStatsType() != OFStatsType.FLOW) {
333 pushFlowMetrics(dpid, (OFFlowStatsReply) msg);
334 }
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800335 break;
336 case BARRIER_REPLY:
337 future = pendingFutures.get(msg.getXid());
338 if (future != null) {
339 future.satisfyRequirement(dpid);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800340 } else {
341 log.warn("Received unknown Barrier Reply: {}", msg.getXid());
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800342 }
343 break;
344 case ERROR:
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800345 log.warn("received Error message {} from {}", msg, dpid);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800346 future = pendingFMs.get(msg.getXid());
347 if (future != null) {
348 future.fail((OFErrorMsg) msg, dpid);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800349 } else {
350 log.warn("Received unknown Error Reply: {} {}", msg.getXid(), msg);
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800351 }
352 break;
353 default:
354 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700355 }
356
357 }
358
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700359 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700360 public void receivedRoleReply(Dpid dpid, RoleState requested,
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800361 RoleState response) {
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700362 // Do nothing here for now.
363 }
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700364
sangho89bf6fb2015-02-09 09:33:13 -0800365 private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) {
alshabib64def642014-12-02 23:27:37 -0800366
alshabib54ce5892014-09-23 17:50:51 -0700367 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib54ce5892014-09-23 17:50:51 -0700368
alshabib64def642014-12-02 23:27:37 -0800369 List<FlowEntry> flowEntries = replies.getEntries().stream()
370 .filter(entry -> !tableMissRule(dpid, entry))
371 .map(entry -> new FlowEntryBuilder(dpid, entry).build())
372 .collect(Collectors.toList());
alshabib54ce5892014-09-23 17:50:51 -0700373
alshabib64def642014-12-02 23:27:37 -0800374 providerService.pushFlowMetrics(did, flowEntries);
375
alshabib5c370ff2014-09-18 10:12:14 -0700376 }
377
alshabib19fdc122014-10-03 11:38:19 -0700378 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800379 if (reply.getMatch().getMatchFields().iterator().hasNext()) {
alshabib19fdc122014-10-03 11:38:19 -0700380 return false;
381 }
Jonathan Hart2ffcd102015-01-16 16:47:50 -0800382 if (reply.getVersion().equals(OFVersion.OF_10)) {
383 return reply.getPriority() == LOWEST_PRIORITY
384 && reply.getActions().isEmpty();
385 }
alshabib19fdc122014-10-03 11:38:19 -0700386 for (OFInstruction ins : reply.getInstructions()) {
387 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
388 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
389 List<OFAction> acts = apply.getActions();
390 for (OFAction act : acts) {
391 if (act.getType() == OFActionType.OUTPUT) {
392 OFActionOutput out = (OFActionOutput) act;
393 if (out.getPort() == OFPort.CONTROLLER) {
394 return true;
395 }
396 }
397 }
398 }
399 }
400 return false;
401 }
Ayaka Koshibe38594c22014-10-22 13:36:12 -0700402
alshabib8f1cf4a2014-09-17 14:44:48 -0700403 }
alshabib1cc04f72014-09-16 16:09:58 -0700404
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800405 private class InstallationFuture implements Future<CompletedBatchOperation> {
alshabib902d41b2014-10-07 16:52:05 -0700406
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800407 // barrier xid
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800408 private final Long xid;
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800409 // waiting for barrier reply from...
alshabib902d41b2014-10-07 16:52:05 -0700410 private final Set<Dpid> sws;
411 private final AtomicBoolean ok = new AtomicBoolean(true);
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800412 // FlowMod xid ->
alshabib193525b2014-10-08 18:58:03 -0700413 private final Map<Long, FlowRuleBatchEntry> fms;
414
Brian O'Connor427a1762014-11-19 18:40:32 -0800415
Madan Jampani117aaae2014-10-23 10:04:05 -0700416 private final Set<FlowEntry> offendingFlowMods = Sets.newHashSet();
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800417 // Failed batch operation id
Sho SHIMIZUc0e8bfa2015-01-22 16:15:08 -0800418 private Long failedId;
alshabib902d41b2014-10-07 16:52:05 -0700419
420 private final CountDownLatch countDownLatch;
alshabib193525b2014-10-08 18:58:03 -0700421 private BatchState state;
alshabib902d41b2014-10-07 16:52:05 -0700422
alshabib193525b2014-10-08 18:58:03 -0700423 public InstallationFuture(Set<Dpid> sws, Map<Long, FlowRuleBatchEntry> fmXids) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800424 this.xid = xidCounter.getAndIncrement();
alshabib193525b2014-10-08 18:58:03 -0700425 this.state = BatchState.STARTED;
alshabib902d41b2014-10-07 16:52:05 -0700426 this.sws = sws;
alshabib193525b2014-10-08 18:58:03 -0700427 this.fms = fmXids;
alshabib902d41b2014-10-07 16:52:05 -0700428 countDownLatch = new CountDownLatch(sws.size());
429 }
430
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800431 public Long xid() {
432 return xid;
433 }
434
alshabib902d41b2014-10-07 16:52:05 -0700435 public void fail(OFErrorMsg msg, Dpid dpid) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700436
alshabib902d41b2014-10-07 16:52:05 -0700437 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700438 FlowEntry fe = null;
439 FlowRuleBatchEntry fbe = fms.get(msg.getXid());
Brian O'Connor427a1762014-11-19 18:40:32 -0800440 failedId = fbe.id();
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800441 FlowRule offending = fbe.target();
alshabib902d41b2014-10-07 16:52:05 -0700442 //TODO handle specific error msgs
alshabib902d41b2014-10-07 16:52:05 -0700443 switch (msg.getErrType()) {
444 case BAD_ACTION:
alshabib193525b2014-10-08 18:58:03 -0700445 OFBadActionErrorMsg bad = (OFBadActionErrorMsg) msg;
446 fe = new DefaultFlowEntry(offending, bad.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800447 bad.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700448 break;
449 case BAD_INSTRUCTION:
alshabib193525b2014-10-08 18:58:03 -0700450 OFBadInstructionErrorMsg badins = (OFBadInstructionErrorMsg) msg;
451 fe = new DefaultFlowEntry(offending, badins.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800452 badins.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700453 break;
454 case BAD_MATCH:
alshabib193525b2014-10-08 18:58:03 -0700455 OFBadMatchErrorMsg badMatch = (OFBadMatchErrorMsg) msg;
456 fe = new DefaultFlowEntry(offending, badMatch.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800457 badMatch.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700458 break;
459 case BAD_REQUEST:
alshabib193525b2014-10-08 18:58:03 -0700460 OFBadRequestErrorMsg badReq = (OFBadRequestErrorMsg) msg;
461 fe = new DefaultFlowEntry(offending, badReq.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800462 badReq.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700463 break;
464 case FLOW_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700465 OFFlowModFailedErrorMsg fmFail = (OFFlowModFailedErrorMsg) msg;
466 fe = new DefaultFlowEntry(offending, fmFail.getErrType().ordinal(),
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800467 fmFail.getCode().ordinal());
alshabib902d41b2014-10-07 16:52:05 -0700468 break;
alshabib193525b2014-10-08 18:58:03 -0700469 case EXPERIMENTER:
alshabib902d41b2014-10-07 16:52:05 -0700470 case GROUP_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700471 case HELLO_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700472 case METER_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700473 case PORT_MOD_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700474 case QUEUE_OP_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700475 case ROLE_REQUEST_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700476 case SWITCH_CONFIG_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700477 case TABLE_FEATURES_FAILED:
alshabib902d41b2014-10-07 16:52:05 -0700478 case TABLE_MOD_FAILED:
alshabib193525b2014-10-08 18:58:03 -0700479 fe = new DefaultFlowEntry(offending, msg.getErrType().ordinal(), 0);
alshabib902d41b2014-10-07 16:52:05 -0700480 break;
481 default:
alshabib193525b2014-10-08 18:58:03 -0700482 log.error("Unknown error type {}", msg.getErrType());
alshabib902d41b2014-10-07 16:52:05 -0700483
484 }
alshabib193525b2014-10-08 18:58:03 -0700485 offendingFlowMods.add(fe);
alshabib902d41b2014-10-07 16:52:05 -0700486
Yuta HIGUCHI804a4bb2014-11-27 09:37:34 -0800487 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700488 }
489
alshabib193525b2014-10-08 18:58:03 -0700490
alshabib902d41b2014-10-07 16:52:05 -0700491 public void satisfyRequirement(Dpid dpid) {
alshabib3effd042014-10-17 12:00:31 -0700492 log.debug("Satisfaction from switch {}", dpid);
alshabib7911a052014-10-16 17:49:37 -0700493 removeRequirement(dpid);
alshabib902d41b2014-10-07 16:52:05 -0700494 }
495
alshabib193525b2014-10-08 18:58:03 -0700496
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800497 public void verify() {
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800498 checkState(!sws.isEmpty());
alshabib902d41b2014-10-07 16:52:05 -0700499 for (Dpid dpid : sws) {
500 OpenFlowSwitch sw = controller.getSwitch(dpid);
501 OFBarrierRequest.Builder builder = sw.factory()
502 .buildBarrierRequest()
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800503 .setXid(xid);
alshabib902d41b2014-10-07 16:52:05 -0700504 sw.sendMsg(builder.build());
505 }
alshabib902d41b2014-10-07 16:52:05 -0700506 }
507
508 @Override
509 public boolean cancel(boolean mayInterruptIfRunning) {
Madan Jampani117aaae2014-10-23 10:04:05 -0700510 if (isDone()) {
511 return false;
512 }
alshabib7911a052014-10-16 17:49:37 -0700513 ok.set(false);
alshabib193525b2014-10-08 18:58:03 -0700514 this.state = BatchState.CANCELLED;
515 cleanUp();
516 for (FlowRuleBatchEntry fbe : fms.values()) {
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800517 if (fbe.operator() == FlowRuleOperation.ADD ||
518 fbe.operator() == FlowRuleOperation.MODIFY) {
519 removeFlowRule(fbe.target());
520 } else if (fbe.operator() == FlowRuleOperation.REMOVE) {
521 applyRule(fbe.target());
alshabib193525b2014-10-08 18:58:03 -0700522 }
523
524 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700525 return true;
alshabib902d41b2014-10-07 16:52:05 -0700526 }
527
528 @Override
529 public boolean isCancelled() {
alshabib193525b2014-10-08 18:58:03 -0700530 return this.state == BatchState.CANCELLED;
alshabib902d41b2014-10-07 16:52:05 -0700531 }
532
533 @Override
534 public boolean isDone() {
Madan Jampani117aaae2014-10-23 10:04:05 -0700535 return this.state == BatchState.FINISHED || isCancelled();
alshabib902d41b2014-10-07 16:52:05 -0700536 }
537
538 @Override
alshabib193525b2014-10-08 18:58:03 -0700539 public CompletedBatchOperation get() throws InterruptedException, ExecutionException {
alshabib902d41b2014-10-07 16:52:05 -0700540 countDownLatch.await();
alshabib193525b2014-10-08 18:58:03 -0700541 this.state = BatchState.FINISHED;
Sho SHIMIZUc0e8bfa2015-01-22 16:15:08 -0800542 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800543 CompletedBatchOperation result =
544 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
545 //FIXME do cleanup here (moved by BOC)
546 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700547 return result;
alshabib902d41b2014-10-07 16:52:05 -0700548 }
549
550 @Override
alshabib193525b2014-10-08 18:58:03 -0700551 public CompletedBatchOperation get(long timeout, TimeUnit unit)
alshabib902d41b2014-10-07 16:52:05 -0700552 throws InterruptedException, ExecutionException,
553 TimeoutException {
alshabib26834582014-10-08 20:15:46 -0700554 if (countDownLatch.await(timeout, unit)) {
555 this.state = BatchState.FINISHED;
Sho SHIMIZUc0e8bfa2015-01-22 16:15:08 -0800556 Set<Long> failedIds = (failedId != null) ? Sets.newHashSet(failedId) : Collections.emptySet();
Brian O'Connor427a1762014-11-19 18:40:32 -0800557 CompletedBatchOperation result =
558 new CompletedBatchOperation(ok.get(), offendingFlowMods, failedIds);
559 // FIXME do cleanup here (moved by BOC)
560 cleanUp();
Madan Jampani117aaae2014-10-23 10:04:05 -0700561 return result;
alshabib26834582014-10-08 20:15:46 -0700562 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800563 throw new TimeoutException(this.toString());
alshabib193525b2014-10-08 18:58:03 -0700564 }
565
566 private void cleanUp() {
alshabib7911a052014-10-16 17:49:37 -0700567 if (isDone() || isCancelled()) {
Thomas Vachuska9b2da212014-11-10 19:30:25 -0800568 pendingFutures.remove(xid);
alshabib193525b2014-10-08 18:58:03 -0700569 for (Long xid : fms.keySet()) {
570 pendingFMs.remove(xid);
571 }
572 }
alshabib902d41b2014-10-07 16:52:05 -0700573 }
574
alshabib7911a052014-10-16 17:49:37 -0700575 private void removeRequirement(Dpid dpid) {
576 countDownLatch.countDown();
577 sws.remove(dpid);
Brian O'Connor427a1762014-11-19 18:40:32 -0800578 //FIXME don't do cleanup here (moved by BOC)
579 //cleanUp();
alshabib7911a052014-10-16 17:49:37 -0700580 }
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800581
582 @Override
583 public String toString() {
584 return MoreObjects.toStringHelper(getClass())
585 .add("xid", xid)
586 .add("pending devices", sws)
587 .add("devices in batch",
588 fms.values().stream()
Sho SHIMIZUaba9d002015-01-29 14:51:04 -0800589 .map((fbe) -> fbe.target().deviceId())
Yuta HIGUCHI82e53262014-11-27 10:28:51 -0800590 .distinct().collect(Collectors.toList()))
591 .add("failedId", failedId)
592 .add("latchCount", countDownLatch.getCount())
593 .add("state", state)
594 .add("no error?", ok.get())
595 .toString();
596 }
alshabib902d41b2014-10-07 16:52:05 -0700597 }
alshabiba68eb962014-09-24 20:34:13 -0700598
alshabib1cc04f72014-09-16 16:09:58 -0700599}