blob: 0aca754a42cd420315d07fa623d2a7bafea0fa28 [file] [log] [blame]
alshabib1cc04f72014-09-16 16:09:58 -07001package org.onlab.onos.provider.of.flow.impl;
2
3import static org.slf4j.LoggerFactory.getLogger;
4
alshabib902d41b2014-10-07 16:52:05 -07005import java.util.HashSet;
alshabib19fdc122014-10-03 11:38:19 -07006import java.util.List;
alshabibeec3a062014-09-17 18:01:26 -07007import java.util.Map;
alshabib902d41b2014-10-07 16:52:05 -07008import java.util.Set;
9import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.CountDownLatch;
11import java.util.concurrent.ExecutionException;
12import java.util.concurrent.Future;
13import java.util.concurrent.TimeUnit;
14import java.util.concurrent.TimeoutException;
15import java.util.concurrent.atomic.AtomicBoolean;
alshabibeec3a062014-09-17 18:01:26 -070016
alshabib1cc04f72014-09-16 16:09:58 -070017import org.apache.felix.scr.annotations.Activate;
18import org.apache.felix.scr.annotations.Component;
19import org.apache.felix.scr.annotations.Deactivate;
20import org.apache.felix.scr.annotations.Reference;
21import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabiba68eb962014-09-24 20:34:13 -070022import org.onlab.onos.ApplicationId;
alshabiba7f7ca82014-09-22 11:41:23 -070023import org.onlab.onos.net.DeviceId;
alshabib1c319ff2014-10-04 20:29:09 -070024import org.onlab.onos.net.flow.FlowEntry;
alshabib1cc04f72014-09-16 16:09:58 -070025import org.onlab.onos.net.flow.FlowRule;
alshabib902d41b2014-10-07 16:52:05 -070026import org.onlab.onos.net.flow.FlowRuleBatchEntry;
alshabib1cc04f72014-09-16 16:09:58 -070027import org.onlab.onos.net.flow.FlowRuleProvider;
28import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
29import org.onlab.onos.net.flow.FlowRuleProviderService;
alshabib902d41b2014-10-07 16:52:05 -070030import org.onlab.onos.net.intent.BatchOperation;
alshabib1cc04f72014-09-16 16:09:58 -070031import org.onlab.onos.net.provider.AbstractProvider;
32import org.onlab.onos.net.provider.ProviderId;
33import org.onlab.onos.net.topology.TopologyService;
tom9c94c5b2014-09-17 13:14:42 -070034import org.onlab.onos.openflow.controller.Dpid;
35import org.onlab.onos.openflow.controller.OpenFlowController;
alshabibeec3a062014-09-17 18:01:26 -070036import org.onlab.onos.openflow.controller.OpenFlowEventListener;
tom9c94c5b2014-09-17 13:14:42 -070037import org.onlab.onos.openflow.controller.OpenFlowSwitch;
alshabibce4e5782014-09-17 14:56:42 -070038import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -070039import org.onlab.onos.openflow.controller.RoleState;
alshabib19fdc122014-10-03 11:38:19 -070040import org.projectfloodlight.openflow.protocol.OFActionType;
alshabib902d41b2014-10-07 16:52:05 -070041import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
42import org.projectfloodlight.openflow.protocol.OFErrorMsg;
alshabib8f1cf4a2014-09-17 14:44:48 -070043import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070044import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
45import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070046import org.projectfloodlight.openflow.protocol.OFInstructionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070047import org.projectfloodlight.openflow.protocol.OFMessage;
48import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070049import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib54ce5892014-09-23 17:50:51 -070050import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
alshabib5c370ff2014-09-18 10:12:14 -070051import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabib19fdc122014-10-03 11:38:19 -070052import org.projectfloodlight.openflow.protocol.OFVersion;
53import org.projectfloodlight.openflow.protocol.action.OFAction;
54import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
55import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
56import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
57import org.projectfloodlight.openflow.types.OFPort;
alshabib902d41b2014-10-07 16:52:05 -070058import org.projectfloodlight.openflow.types.U32;
alshabib1cc04f72014-09-16 16:09:58 -070059import org.slf4j.Logger;
60
alshabib54ce5892014-09-23 17:50:51 -070061import com.google.common.collect.ArrayListMultimap;
alshabib902d41b2014-10-07 16:52:05 -070062import com.google.common.collect.Lists;
alshabib5c370ff2014-09-18 10:12:14 -070063import com.google.common.collect.Maps;
alshabib54ce5892014-09-23 17:50:51 -070064import com.google.common.collect.Multimap;
alshabibeec3a062014-09-17 18:01:26 -070065
alshabib1cc04f72014-09-16 16:09:58 -070066/**
67 * Provider which uses an OpenFlow controller to detect network
68 * end-station hosts.
69 */
70@Component(immediate = true)
71public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
72
73 private final Logger log = getLogger(getClass());
74
75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected FlowRuleProviderRegistry providerRegistry;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected OpenFlowController controller;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected TopologyService topologyService;
83
84 private FlowRuleProviderService providerService;
85
alshabibeec3a062014-09-17 18:01:26 -070086 private final InternalFlowProvider listener = new InternalFlowProvider();
87
alshabib902d41b2014-10-07 16:52:05 -070088 private final Map<Long, InstallationFuture> pendingFutures =
89 new ConcurrentHashMap<Long, InstallationFuture>();
90
alshabib1cc04f72014-09-16 16:09:58 -070091 /**
92 * Creates an OpenFlow host provider.
93 */
94 public OpenFlowRuleProvider() {
tom7e02cda2014-09-18 12:05:46 -070095 super(new ProviderId("of", "org.onlab.onos.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -070096 }
97
98 @Activate
99 public void activate() {
100 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -0700101 controller.addListener(listener);
102 controller.addEventListener(listener);
alshabib1cc04f72014-09-16 16:09:58 -0700103 log.info("Started");
104 }
105
106 @Deactivate
107 public void deactivate() {
108 providerRegistry.unregister(this);
109 providerService = null;
110
111 log.info("Stopped");
112 }
113 @Override
114 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -0700115 for (int i = 0; i < flowRules.length; i++) {
116 applyRule(flowRules[i]);
117 }
alshabib1cc04f72014-09-16 16:09:58 -0700118 }
119
alshabib35edb1a2014-09-16 17:44:44 -0700120 private void applyRule(FlowRule flowRule) {
121 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
alshabib902d41b2014-10-07 16:52:05 -0700122 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd());
alshabib35edb1a2014-09-16 17:44:44 -0700123 }
124
alshabib35edb1a2014-09-16 17:44:44 -0700125
alshabib35edb1a2014-09-16 17:44:44 -0700126
alshabib1cc04f72014-09-16 16:09:58 -0700127 @Override
128 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700129 for (int i = 0; i < flowRules.length; i++) {
130 removeRule(flowRules[i]);
131 }
alshabib1cc04f72014-09-16 16:09:58 -0700132
133 }
134
alshabib219ebaa2014-09-22 15:41:24 -0700135 private void removeRule(FlowRule flowRule) {
136 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
137 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
138 }
139
alshabiba68eb962014-09-24 20:34:13 -0700140 @Override
141 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
142 // TODO: optimize using the ApplicationId
143 removeFlowRule(flowRules);
144 }
145
alshabib219ebaa2014-09-22 15:41:24 -0700146
alshabib1cc04f72014-09-16 16:09:58 -0700147 //TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
148 // possibly barriers as well. May not be internal at all...
alshabib8f1cf4a2014-09-17 14:44:48 -0700149 private class InternalFlowProvider
150 implements OpenFlowSwitchListener, OpenFlowEventListener {
151
alshabibeec3a062014-09-17 18:01:26 -0700152 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
alshabib1c319ff2014-10-04 20:29:09 -0700153 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700154 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700155
156 @Override
157 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700158 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700159 fsc.start();
160 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700161 }
162
163 @Override
164 public void switchRemoved(Dpid dpid) {
alshabibeec3a062014-09-17 18:01:26 -0700165 collectors.remove(dpid).stop();
alshabib8f1cf4a2014-09-17 14:44:48 -0700166 }
167
168 @Override
169 public void portChanged(Dpid dpid, OFPortStatus status) {
170 //TODO: Decide whether to evict flows internal store.
171 }
172
173 @Override
174 public void handleMessage(Dpid dpid, OFMessage msg) {
alshabib902d41b2014-10-07 16:52:05 -0700175 InstallationFuture future = null;
alshabib8f1cf4a2014-09-17 14:44:48 -0700176 switch (msg.getType()) {
177 case FLOW_REMOVED:
alshabibeec3a062014-09-17 18:01:26 -0700178 //TODO: make this better
alshabib8f1cf4a2014-09-17 14:44:48 -0700179 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700180
alshabib1c319ff2014-10-04 20:29:09 -0700181 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
alshabib8f1cf4a2014-09-17 14:44:48 -0700182 providerService.flowRemoved(fr);
183 break;
184 case STATS_REPLY:
alshabib97044902014-09-18 14:52:16 -0700185 pushFlowMetrics(dpid, (OFStatsReply) msg);
alshabibeec3a062014-09-17 18:01:26 -0700186 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700187 case BARRIER_REPLY:
alshabib902d41b2014-10-07 16:52:05 -0700188 future = pendingFutures.get(msg.getXid());
189 if (future != null) {
190 future.satisfyRequirement(dpid);
191 }
192 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700193 case ERROR:
alshabib902d41b2014-10-07 16:52:05 -0700194 future = pendingFutures.get(msg.getXid());
195 if (future != null) {
196 future.fail((OFErrorMsg) msg, dpid);
197 }
198 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700199 default:
alshabib6eb438a2014-10-01 16:39:37 -0700200 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700201 }
202
203 }
204
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700205 @Override
206 public void roleAssertFailed(Dpid dpid, RoleState role) {
207 // TODO Auto-generated method stub
208
209 }
210
alshabib54ce5892014-09-23 17:50:51 -0700211 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib5c370ff2014-09-18 10:12:14 -0700212 if (stats.getStatsType() != OFStatsType.FLOW) {
213 return;
214 }
alshabib54ce5892014-09-23 17:50:51 -0700215 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700216 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700217 //final List<FlowRule> entries = Lists.newLinkedList();
218
alshabib5c370ff2014-09-18 10:12:14 -0700219 for (OFFlowStatsEntry reply : replies.getEntries()) {
alshabib19fdc122014-10-03 11:38:19 -0700220 if (!tableMissRule(dpid, reply)) {
alshabib1c319ff2014-10-04 20:29:09 -0700221 completeEntries.put(did, new FlowEntryBuilder(dpid, reply).build());
alshabib19fdc122014-10-03 11:38:19 -0700222 }
alshabib5c370ff2014-09-18 10:12:14 -0700223 }
alshabib54ce5892014-09-23 17:50:51 -0700224
225 if (!stats.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
226 log.debug("sending flowstats to core {}", completeEntries.get(did));
227 providerService.pushFlowMetrics(did, completeEntries.get(did));
228 completeEntries.removeAll(did);
229 }
alshabib5c370ff2014-09-18 10:12:14 -0700230 }
231
alshabib19fdc122014-10-03 11:38:19 -0700232 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
233 // TODO NEED TO FIND A BETTER WAY TO AVOID DOING THIS
234 if (reply.getVersion().equals(OFVersion.OF_10) ||
235 reply.getMatch().getMatchFields().iterator().hasNext()) {
236 return false;
237 }
238 for (OFInstruction ins : reply.getInstructions()) {
239 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
240 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
241 List<OFAction> acts = apply.getActions();
242 for (OFAction act : acts) {
243 if (act.getType() == OFActionType.OUTPUT) {
244 OFActionOutput out = (OFActionOutput) act;
245 if (out.getPort() == OFPort.CONTROLLER) {
246 return true;
247 }
248 }
249 }
250 }
251 }
252 return false;
253 }
254
alshabib8f1cf4a2014-09-17 14:44:48 -0700255 }
alshabib1cc04f72014-09-16 16:09:58 -0700256
257
alshabib902d41b2014-10-07 16:52:05 -0700258 @Override
259 public Future<Void> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) {
260 final Set<Dpid> sws = new HashSet<Dpid>();
alshabiba68eb962014-09-24 20:34:13 -0700261
alshabib902d41b2014-10-07 16:52:05 -0700262 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
263 FlowRule flowRule = fbe.getTarget();
264 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
265 sws.add(new Dpid(sw.getId()));
266 switch (fbe.getOperator()) {
267 case ADD:
268 //TODO: Track XID for each flowmod
269 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowAdd());
270 break;
271 case REMOVE:
272 //TODO: Track XID for each flowmod
273 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
274 break;
275 case MODIFY:
276 //TODO: Track XID for each flowmod
277 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod());
278 break;
279 default:
280 log.error("Unsupported batch operation {}", fbe.getOperator());
281 }
282 }
283 InstallationFuture installation = new InstallationFuture(sws);
284 pendingFutures.put(U32.f(batch.hashCode()), installation);
285 installation.verify(batch.hashCode());
286 return installation;
287 }
288
289 private class InstallationFuture implements Future<Void> {
290
291 private final Set<Dpid> sws;
292 private final AtomicBoolean ok = new AtomicBoolean(true);
293 private final List<FlowEntry> offendingFlowMods = Lists.newLinkedList();
294
295 private final CountDownLatch countDownLatch;
296
297 public InstallationFuture(Set<Dpid> sws) {
298 this.sws = sws;
299 countDownLatch = new CountDownLatch(sws.size());
300 }
301
302 public void fail(OFErrorMsg msg, Dpid dpid) {
303 ok.set(false);
304 //TODO add reason to flowentry
305 //TODO handle specific error msgs
306 //offendingFlowMods.add(new FlowEntryBuilder(dpid, msg.));
307 switch (msg.getErrType()) {
308 case BAD_ACTION:
309 break;
310 case BAD_INSTRUCTION:
311 break;
312 case BAD_MATCH:
313 break;
314 case BAD_REQUEST:
315 break;
316 case EXPERIMENTER:
317 break;
318 case FLOW_MOD_FAILED:
319 break;
320 case GROUP_MOD_FAILED:
321 break;
322 case HELLO_FAILED:
323 break;
324 case METER_MOD_FAILED:
325 break;
326 case PORT_MOD_FAILED:
327 break;
328 case QUEUE_OP_FAILED:
329 break;
330 case ROLE_REQUEST_FAILED:
331 break;
332 case SWITCH_CONFIG_FAILED:
333 break;
334 case TABLE_FEATURES_FAILED:
335 break;
336 case TABLE_MOD_FAILED:
337 break;
338 default:
339 break;
340
341 }
342
343 }
344
345 public void satisfyRequirement(Dpid dpid) {
346 log.warn("Satisfaction from switch {}", dpid);
347 sws.remove(controller.getSwitch(dpid));
348 countDownLatch.countDown();
349 }
350
351 public void verify(Integer id) {
352 for (Dpid dpid : sws) {
353 OpenFlowSwitch sw = controller.getSwitch(dpid);
354 OFBarrierRequest.Builder builder = sw.factory()
355 .buildBarrierRequest()
356 .setXid(id);
357 sw.sendMsg(builder.build());
358 }
359
360
361 }
362
363 @Override
364 public boolean cancel(boolean mayInterruptIfRunning) {
365 // TODO Auto-generated method stub
366 return false;
367 }
368
369 @Override
370 public boolean isCancelled() {
371 // TODO Auto-generated method stub
372 return false;
373 }
374
375 @Override
376 public boolean isDone() {
377 return sws.isEmpty();
378 }
379
380 @Override
381 public Void get() throws InterruptedException, ExecutionException {
382 countDownLatch.await();
383 //return offendingFlowMods;
384 return null;
385 }
386
387 @Override
388 public Void get(long timeout, TimeUnit unit)
389 throws InterruptedException, ExecutionException,
390 TimeoutException {
391 countDownLatch.await(timeout, unit);
392 //return offendingFlowMods;
393 return null;
394 }
395
396 }
alshabiba68eb962014-09-24 20:34:13 -0700397
alshabib1cc04f72014-09-16 16:09:58 -0700398}