blob: a9eddd8ce144574ce5c014ca3ae79eb1748b5a71 [file] [log] [blame]
tombe988312014-09-19 18:38:47 -07001package org.onlab.onos.net.flow.impl;
alshabib57044ba2014-09-16 15:58:01 -07002
alshabibbb42cad2014-09-25 11:43:05 -07003import static com.google.common.base.Preconditions.checkNotNull;
4import static org.slf4j.LoggerFactory.getLogger;
5
6import java.util.Iterator;
7import java.util.List;
alshabib902d41b2014-10-07 16:52:05 -07008import java.util.concurrent.ExecutionException;
9import java.util.concurrent.Future;
10import java.util.concurrent.TimeUnit;
11import java.util.concurrent.TimeoutException;
alshabibbb42cad2014-09-25 11:43:05 -070012
alshabib57044ba2014-09-16 15:58:01 -070013import org.apache.felix.scr.annotations.Activate;
14import org.apache.felix.scr.annotations.Component;
15import org.apache.felix.scr.annotations.Deactivate;
16import org.apache.felix.scr.annotations.Reference;
17import org.apache.felix.scr.annotations.ReferenceCardinality;
18import org.apache.felix.scr.annotations.Service;
alshabiba68eb962014-09-24 20:34:13 -070019import org.onlab.onos.ApplicationId;
alshabib57044ba2014-09-16 15:58:01 -070020import org.onlab.onos.event.AbstractListenerRegistry;
21import org.onlab.onos.event.EventDeliveryService;
22import org.onlab.onos.net.Device;
23import org.onlab.onos.net.DeviceId;
24import org.onlab.onos.net.device.DeviceService;
alshabib902d41b2014-10-07 16:52:05 -070025import org.onlab.onos.net.flow.CompletedBatchOperation;
alshabib1c319ff2014-10-04 20:29:09 -070026import org.onlab.onos.net.flow.FlowEntry;
alshabib57044ba2014-09-16 15:58:01 -070027import org.onlab.onos.net.flow.FlowRule;
alshabib902d41b2014-10-07 16:52:05 -070028import org.onlab.onos.net.flow.FlowRuleBatchEntry;
29import org.onlab.onos.net.flow.FlowRuleBatchOperation;
alshabib57044ba2014-09-16 15:58:01 -070030import org.onlab.onos.net.flow.FlowRuleEvent;
31import org.onlab.onos.net.flow.FlowRuleListener;
32import org.onlab.onos.net.flow.FlowRuleProvider;
33import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
34import org.onlab.onos.net.flow.FlowRuleProviderService;
35import org.onlab.onos.net.flow.FlowRuleService;
tombe988312014-09-19 18:38:47 -070036import org.onlab.onos.net.flow.FlowRuleStore;
tomc78acee2014-09-24 15:16:55 -070037import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
alshabib57044ba2014-09-16 15:58:01 -070038import org.onlab.onos.net.provider.AbstractProviderRegistry;
39import org.onlab.onos.net.provider.AbstractProviderService;
40import org.slf4j.Logger;
41
alshabib902d41b2014-10-07 16:52:05 -070042import com.google.common.collect.ArrayListMultimap;
alshabibbb42cad2014-09-25 11:43:05 -070043import com.google.common.collect.Lists;
alshabib902d41b2014-10-07 16:52:05 -070044import com.google.common.collect.Multimap;
alshabiba7f7ca82014-09-22 11:41:23 -070045
tome4729872014-09-23 00:37:37 -070046/**
47 * Provides implementation of the flow NB & SB APIs.
48 */
alshabib57044ba2014-09-16 15:58:01 -070049@Component(immediate = true)
50@Service
tom202175a2014-09-19 19:00:11 -070051public class FlowRuleManager
tom9b4030d2014-10-06 10:39:03 -070052 extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
53 implements FlowRuleService, FlowRuleProviderRegistry {
alshabib57044ba2014-09-16 15:58:01 -070054
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070055 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
alshabib57044ba2014-09-16 15:58:01 -070056 private final Logger log = getLogger(getClass());
57
58 private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
tom9b4030d2014-10-06 10:39:03 -070059 listenerRegistry = new AbstractListenerRegistry<>();
alshabib57044ba2014-09-16 15:58:01 -070060
alshabibbb42cad2014-09-25 11:43:05 -070061 private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
tomc78acee2014-09-24 15:16:55 -070062
tombe988312014-09-19 18:38:47 -070063 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected FlowRuleStore store;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070065
alshabib57044ba2014-09-16 15:58:01 -070066 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070067 protected EventDeliveryService eventDispatcher;
alshabib57044ba2014-09-16 15:58:01 -070068
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070070 protected DeviceService deviceService;
alshabib57044ba2014-09-16 15:58:01 -070071
72 @Activate
73 public void activate() {
tomc78acee2014-09-24 15:16:55 -070074 store.setDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070075 eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
76 log.info("Started");
77 }
78
79 @Deactivate
80 public void deactivate() {
tomc78acee2014-09-24 15:16:55 -070081 store.unsetDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070082 eventDispatcher.removeSink(FlowRuleEvent.class);
83 log.info("Stopped");
84 }
85
86 @Override
tom9b4030d2014-10-06 10:39:03 -070087 public int getFlowRuleCount() {
88 return store.getFlowRuleCount();
89 }
90
91 @Override
alshabib1c319ff2014-10-04 20:29:09 -070092 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070093 return store.getFlowEntries(deviceId);
alshabib57044ba2014-09-16 15:58:01 -070094 }
95
96 @Override
alshabib219ebaa2014-09-22 15:41:24 -070097 public void applyFlowRules(FlowRule... flowRules) {
alshabib57044ba2014-09-16 15:58:01 -070098 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -070099 FlowRule f = flowRules[i];
alshabib57044ba2014-09-16 15:58:01 -0700100 final Device device = deviceService.getDevice(f.deviceId());
101 final FlowRuleProvider frp = getProvider(device.providerId());
alshabib219ebaa2014-09-22 15:41:24 -0700102 store.storeFlowRule(f);
alshabib57044ba2014-09-16 15:58:01 -0700103 frp.applyFlowRule(f);
104 }
alshabib57044ba2014-09-16 15:58:01 -0700105 }
106
107 @Override
108 public void removeFlowRules(FlowRule... flowRules) {
alshabibbb8b1282014-09-22 17:00:18 -0700109 FlowRule f;
alshabiba68eb962014-09-24 20:34:13 -0700110 FlowRuleProvider frp;
111 Device device;
alshabib57044ba2014-09-16 15:58:01 -0700112 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -0700113 f = flowRules[i];
114 device = deviceService.getDevice(f.deviceId());
alshabib219ebaa2014-09-22 15:41:24 -0700115 store.deleteFlowRule(f);
tom7951b232014-10-06 13:35:30 -0700116 if (device != null) {
117 frp = getProvider(device.providerId());
118 frp.removeFlowRule(f);
119 }
alshabib57044ba2014-09-16 15:58:01 -0700120 }
alshabiba68eb962014-09-24 20:34:13 -0700121 }
alshabib57044ba2014-09-16 15:58:01 -0700122
alshabiba68eb962014-09-24 20:34:13 -0700123 @Override
124 public void removeFlowRulesById(ApplicationId id) {
tom9b4030d2014-10-06 10:39:03 -0700125 Iterable<FlowRule> rules = getFlowRulesById(id);
alshabiba68eb962014-09-24 20:34:13 -0700126 FlowRuleProvider frp;
127 Device device;
alshabibbb42cad2014-09-25 11:43:05 -0700128
alshabiba68eb962014-09-24 20:34:13 -0700129 for (FlowRule f : rules) {
130 store.deleteFlowRule(f);
131 device = deviceService.getDevice(f.deviceId());
132 frp = getProvider(device.providerId());
133 frp.removeRulesById(id, f);
134 }
135 }
136
137 @Override
138 public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
alshabib1c319ff2014-10-04 20:29:09 -0700139 return store.getFlowRulesByAppId(id);
alshabib57044ba2014-09-16 15:58:01 -0700140 }
141
142 @Override
alshabib902d41b2014-10-07 16:52:05 -0700143 public Future<CompletedBatchOperation> applyBatch(
144 FlowRuleBatchOperation batch) {
145 Multimap<FlowRuleProvider, FlowRuleBatchEntry> batches =
146 ArrayListMultimap.create();
147 List<Future<Void>> futures = Lists.newArrayList();
148 for (FlowRuleBatchEntry fbe : batch.getOperations()) {
149 final FlowRule f = fbe.getTarget();
150 final Device device = deviceService.getDevice(f.deviceId());
151 final FlowRuleProvider frp = getProvider(device.providerId());
152 batches.put(frp, fbe);
153 switch (fbe.getOperator()) {
154 case ADD:
155 store.storeFlowRule(f);
156 break;
157 case REMOVE:
158 store.deleteFlowRule(f);
159 break;
160 case MODIFY:
161 default:
162 log.error("Batch operation type {} unsupported.", fbe.getOperator());
163 }
164 }
165 for (FlowRuleProvider provider : batches.keySet()) {
166 FlowRuleBatchOperation b =
167 new FlowRuleBatchOperation(batches.get(provider));
168 Future<Void> future = provider.executeBatch(b);
169 futures.add(future);
170 }
171 return new FlowRuleBatchFuture(futures);
172 }
173
174 @Override
alshabib57044ba2014-09-16 15:58:01 -0700175 public void addListener(FlowRuleListener listener) {
176 listenerRegistry.addListener(listener);
177 }
178
179 @Override
180 public void removeListener(FlowRuleListener listener) {
181 listenerRegistry.removeListener(listener);
182 }
183
184 @Override
185 protected FlowRuleProviderService createProviderService(
186 FlowRuleProvider provider) {
187 return new InternalFlowRuleProviderService(provider);
188 }
189
190 private class InternalFlowRuleProviderService
tom9b4030d2014-10-06 10:39:03 -0700191 extends AbstractProviderService<FlowRuleProvider>
192 implements FlowRuleProviderService {
alshabib57044ba2014-09-16 15:58:01 -0700193
194 protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
195 super(provider);
196 }
197
198 @Override
alshabib1c319ff2014-10-04 20:29:09 -0700199 public void flowRemoved(FlowEntry flowEntry) {
200 checkNotNull(flowEntry, FLOW_RULE_NULL);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700201 checkValidity();
alshabib1c319ff2014-10-04 20:29:09 -0700202 FlowEntry stored = store.getFlowEntry(flowEntry);
alshabiba68eb962014-09-24 20:34:13 -0700203 if (stored == null) {
alshabib1c319ff2014-10-04 20:29:09 -0700204 log.info("Rule already evicted from store: {}", flowEntry);
alshabiba68eb962014-09-24 20:34:13 -0700205 return;
206 }
alshabib1c319ff2014-10-04 20:29:09 -0700207 Device device = deviceService.getDevice(flowEntry.deviceId());
alshabiba68eb962014-09-24 20:34:13 -0700208 FlowRuleProvider frp = getProvider(device.providerId());
209 FlowRuleEvent event = null;
210 switch (stored.state()) {
tom9b4030d2014-10-06 10:39:03 -0700211 case ADDED:
212 case PENDING_ADD:
alshabib6eb438a2014-10-01 16:39:37 -0700213 frp.applyFlowRule(stored);
tom9b4030d2014-10-06 10:39:03 -0700214 break;
215 case PENDING_REMOVE:
216 case REMOVED:
217 event = store.removeFlowRule(stored);
218 break;
219 default:
220 break;
alshabib57044ba2014-09-16 15:58:01 -0700221
alshabiba68eb962014-09-24 20:34:13 -0700222 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700223 if (event != null) {
alshabib1c319ff2014-10-04 20:29:09 -0700224 log.debug("Flow {} removed", flowEntry);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700225 post(event);
226 }
alshabib57044ba2014-09-16 15:58:01 -0700227 }
228
alshabibba5ac482014-10-02 17:15:20 -0700229
alshabib1c319ff2014-10-04 20:29:09 -0700230 private void flowMissing(FlowEntry flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700231 checkNotNull(flowRule, FLOW_RULE_NULL);
232 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700233 Device device = deviceService.getDevice(flowRule.deviceId());
234 FlowRuleProvider frp = getProvider(device.providerId());
alshabibbb42cad2014-09-25 11:43:05 -0700235 FlowRuleEvent event = null;
alshabiba68eb962014-09-24 20:34:13 -0700236 switch (flowRule.state()) {
tom9b4030d2014-10-06 10:39:03 -0700237 case PENDING_REMOVE:
238 case REMOVED:
239 event = store.removeFlowRule(flowRule);
240 frp.removeFlowRule(flowRule);
241 break;
242 case ADDED:
243 case PENDING_ADD:
244 frp.applyFlowRule(flowRule);
245 break;
246 default:
247 log.debug("Flow {} has not been installed.", flowRule);
alshabiba68eb962014-09-24 20:34:13 -0700248 }
249
alshabibbb42cad2014-09-25 11:43:05 -0700250 if (event != null) {
251 log.debug("Flow {} removed", flowRule);
252 post(event);
253 }
alshabib57044ba2014-09-16 15:58:01 -0700254
255 }
256
alshabibba5ac482014-10-02 17:15:20 -0700257
258 private void extraneousFlow(FlowRule flowRule) {
alshabib219ebaa2014-09-22 15:41:24 -0700259 checkNotNull(flowRule, FLOW_RULE_NULL);
260 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700261 removeFlowRules(flowRule);
alshabib54ce5892014-09-23 17:50:51 -0700262 log.debug("Flow {} is on switch but not in store.", flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700263 }
264
alshabibba5ac482014-10-02 17:15:20 -0700265
alshabib1c319ff2014-10-04 20:29:09 -0700266 private void flowAdded(FlowEntry flowEntry) {
267 checkNotNull(flowEntry, FLOW_RULE_NULL);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700268 checkValidity();
alshabib57044ba2014-09-16 15:58:01 -0700269
alshabib1c319ff2014-10-04 20:29:09 -0700270 if (checkRuleLiveness(flowEntry, store.getFlowEntry(flowEntry))) {
alshabibba5ac482014-10-02 17:15:20 -0700271
alshabib1c319ff2014-10-04 20:29:09 -0700272 FlowRuleEvent event = store.addOrUpdateFlowRule(flowEntry);
alshabibba5ac482014-10-02 17:15:20 -0700273 if (event == null) {
274 log.debug("No flow store event generated.");
275 } else {
alshabib1c319ff2014-10-04 20:29:09 -0700276 log.debug("Flow {} {}", flowEntry, event.type());
alshabibba5ac482014-10-02 17:15:20 -0700277 post(event);
278 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700279 } else {
alshabib1c319ff2014-10-04 20:29:09 -0700280 removeFlowRules(flowEntry);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700281 }
alshabib219ebaa2014-09-22 15:41:24 -0700282
alshabib57044ba2014-09-16 15:58:01 -0700283 }
284
alshabib1c319ff2014-10-04 20:29:09 -0700285 private boolean checkRuleLiveness(FlowEntry swRule, FlowEntry storedRule) {
286 if (storedRule == null) {
287 return false;
288 }
alshabib85c41972014-10-03 13:48:39 -0700289 long timeout = storedRule.timeout() * 1000;
290 Long currentTime = System.currentTimeMillis();
291 if (storedRule.packets() != swRule.packets()) {
alshabib1c319ff2014-10-04 20:29:09 -0700292 storedRule.setLastSeen();
alshabib85c41972014-10-03 13:48:39 -0700293 return true;
294 }
alshabib85c41972014-10-03 13:48:39 -0700295
alshabib1c319ff2014-10-04 20:29:09 -0700296 if ((currentTime - storedRule.lastSeen()) <= timeout) {
alshabibc274c902014-10-03 14:58:27 -0700297 return true;
298 }
299 return false;
alshabibba5ac482014-10-02 17:15:20 -0700300 }
301
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700302 // Posts the specified event to the local event dispatcher.
303 private void post(FlowRuleEvent event) {
304 if (event != null) {
305 eventDispatcher.post(event);
306 }
307 }
alshabib5c370ff2014-09-18 10:12:14 -0700308
309 @Override
alshabib1c319ff2014-10-04 20:29:09 -0700310 public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
311 List<FlowEntry> storedRules = Lists.newLinkedList(store.getFlowEntries(deviceId));
alshabibbb8b1282014-09-22 17:00:18 -0700312
alshabib1c319ff2014-10-04 20:29:09 -0700313 Iterator<FlowEntry> switchRulesIterator = flowEntries.iterator();
alshabiba7f7ca82014-09-22 11:41:23 -0700314
315 while (switchRulesIterator.hasNext()) {
alshabib1c319ff2014-10-04 20:29:09 -0700316 FlowEntry rule = switchRulesIterator.next();
alshabiba7f7ca82014-09-22 11:41:23 -0700317 if (storedRules.remove(rule)) {
alshabib219ebaa2014-09-22 15:41:24 -0700318 // we both have the rule, let's update some info then.
alshabiba7f7ca82014-09-22 11:41:23 -0700319 flowAdded(rule);
320 } else {
alshabib219ebaa2014-09-22 15:41:24 -0700321 // the device has a rule the store does not have
322 extraneousFlow(rule);
alshabiba7f7ca82014-09-22 11:41:23 -0700323 }
324 }
alshabib1c319ff2014-10-04 20:29:09 -0700325 for (FlowEntry rule : storedRules) {
alshabiba7f7ca82014-09-22 11:41:23 -0700326 // there are rules in the store that aren't on the switch
327 flowMissing(rule);
alshabib54ce5892014-09-23 17:50:51 -0700328
alshabiba7f7ca82014-09-22 11:41:23 -0700329 }
alshabib5c370ff2014-09-18 10:12:14 -0700330 }
alshabib57044ba2014-09-16 15:58:01 -0700331 }
332
tomc78acee2014-09-24 15:16:55 -0700333 // Store delegate to re-post events emitted from the store.
334 private class InternalStoreDelegate implements FlowRuleStoreDelegate {
335 @Override
336 public void notify(FlowRuleEvent event) {
337 eventDispatcher.post(event);
338 }
339 }
alshabib902d41b2014-10-07 16:52:05 -0700340
341 private class FlowRuleBatchFuture
342 implements Future<CompletedBatchOperation> {
343
344 private final List<Future<Void>> futures;
345
346 public FlowRuleBatchFuture(List<Future<Void>> futures) {
347 this.futures = futures;
348 }
349
350 @Override
351 public boolean cancel(boolean mayInterruptIfRunning) {
352 // TODO Auto-generated method stub
353 return false;
354 }
355
356 @Override
357 public boolean isCancelled() {
358 // TODO Auto-generated method stub
359 return false;
360 }
361
362 @Override
363 public boolean isDone() {
364 boolean isDone = true;
365 for (Future<Void> future : futures) {
366 isDone &= future.isDone();
367 }
368 return isDone;
369 }
370
371 @Override
372 public CompletedBatchOperation get() throws InterruptedException,
373 ExecutionException {
374 // TODO Auto-generated method stub
375 for (Future<Void> future : futures) {
376 future.get();
377 }
378 return new CompletedBatchOperation();
379 }
380
381 @Override
382 public CompletedBatchOperation get(long timeout, TimeUnit unit)
383 throws InterruptedException, ExecutionException,
384 TimeoutException {
385 // TODO we should decrement the timeout
386 long start = System.nanoTime();
387 long end = start + unit.toNanos(timeout);
388 for (Future<Void> future : futures) {
389 long now = System.nanoTime();
390 long thisTimeout = end - now;
391 future.get(thisTimeout, TimeUnit.NANOSECONDS);
392 }
393 return new CompletedBatchOperation();
394 }
395
396 }
397
398
alshabib57044ba2014-09-16 15:58:01 -0700399}