blob: ce11cea33af8b22ce65114ac8df17b27f96aaaa5 [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;
8
alshabib57044ba2014-09-16 15:58:01 -07009import org.apache.felix.scr.annotations.Activate;
10import org.apache.felix.scr.annotations.Component;
11import org.apache.felix.scr.annotations.Deactivate;
12import org.apache.felix.scr.annotations.Reference;
13import org.apache.felix.scr.annotations.ReferenceCardinality;
14import org.apache.felix.scr.annotations.Service;
alshabiba68eb962014-09-24 20:34:13 -070015import org.onlab.onos.ApplicationId;
alshabib57044ba2014-09-16 15:58:01 -070016import org.onlab.onos.event.AbstractListenerRegistry;
17import org.onlab.onos.event.EventDeliveryService;
18import org.onlab.onos.net.Device;
19import org.onlab.onos.net.DeviceId;
20import org.onlab.onos.net.device.DeviceService;
alshabib1c319ff2014-10-04 20:29:09 -070021import org.onlab.onos.net.flow.FlowEntry;
alshabib57044ba2014-09-16 15:58:01 -070022import org.onlab.onos.net.flow.FlowRule;
23import org.onlab.onos.net.flow.FlowRuleEvent;
24import org.onlab.onos.net.flow.FlowRuleListener;
25import org.onlab.onos.net.flow.FlowRuleProvider;
26import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
27import org.onlab.onos.net.flow.FlowRuleProviderService;
28import org.onlab.onos.net.flow.FlowRuleService;
tombe988312014-09-19 18:38:47 -070029import org.onlab.onos.net.flow.FlowRuleStore;
tomc78acee2014-09-24 15:16:55 -070030import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
alshabib57044ba2014-09-16 15:58:01 -070031import org.onlab.onos.net.provider.AbstractProviderRegistry;
32import org.onlab.onos.net.provider.AbstractProviderService;
33import org.slf4j.Logger;
34
alshabibbb42cad2014-09-25 11:43:05 -070035import com.google.common.collect.Lists;
alshabiba7f7ca82014-09-22 11:41:23 -070036
tome4729872014-09-23 00:37:37 -070037/**
38 * Provides implementation of the flow NB & SB APIs.
39 */
alshabib57044ba2014-09-16 15:58:01 -070040@Component(immediate = true)
41@Service
tom202175a2014-09-19 19:00:11 -070042public class FlowRuleManager
tom9b4030d2014-10-06 10:39:03 -070043 extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
44 implements FlowRuleService, FlowRuleProviderRegistry {
alshabib57044ba2014-09-16 15:58:01 -070045
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070046 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
alshabib57044ba2014-09-16 15:58:01 -070047 private final Logger log = getLogger(getClass());
48
49 private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
tom9b4030d2014-10-06 10:39:03 -070050 listenerRegistry = new AbstractListenerRegistry<>();
alshabib57044ba2014-09-16 15:58:01 -070051
alshabibbb42cad2014-09-25 11:43:05 -070052 private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
tomc78acee2014-09-24 15:16:55 -070053
tombe988312014-09-19 18:38:47 -070054 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
55 protected FlowRuleStore store;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070056
alshabib57044ba2014-09-16 15:58:01 -070057 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070058 protected EventDeliveryService eventDispatcher;
alshabib57044ba2014-09-16 15:58:01 -070059
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070061 protected DeviceService deviceService;
alshabib57044ba2014-09-16 15:58:01 -070062
63 @Activate
64 public void activate() {
tomc78acee2014-09-24 15:16:55 -070065 store.setDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070066 eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
67 log.info("Started");
68 }
69
70 @Deactivate
71 public void deactivate() {
tomc78acee2014-09-24 15:16:55 -070072 store.unsetDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070073 eventDispatcher.removeSink(FlowRuleEvent.class);
74 log.info("Stopped");
75 }
76
77 @Override
tom9b4030d2014-10-06 10:39:03 -070078 public int getFlowRuleCount() {
79 return store.getFlowRuleCount();
80 }
81
82 @Override
alshabib1c319ff2014-10-04 20:29:09 -070083 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070084 return store.getFlowEntries(deviceId);
alshabib57044ba2014-09-16 15:58:01 -070085 }
86
87 @Override
alshabib219ebaa2014-09-22 15:41:24 -070088 public void applyFlowRules(FlowRule... flowRules) {
alshabib57044ba2014-09-16 15:58:01 -070089 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -070090 FlowRule f = flowRules[i];
alshabib57044ba2014-09-16 15:58:01 -070091 final Device device = deviceService.getDevice(f.deviceId());
92 final FlowRuleProvider frp = getProvider(device.providerId());
alshabib219ebaa2014-09-22 15:41:24 -070093 store.storeFlowRule(f);
alshabib57044ba2014-09-16 15:58:01 -070094 frp.applyFlowRule(f);
95 }
alshabib57044ba2014-09-16 15:58:01 -070096 }
97
98 @Override
99 public void removeFlowRules(FlowRule... flowRules) {
alshabibbb8b1282014-09-22 17:00:18 -0700100 FlowRule f;
alshabiba68eb962014-09-24 20:34:13 -0700101 FlowRuleProvider frp;
102 Device device;
alshabib57044ba2014-09-16 15:58:01 -0700103 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -0700104 f = flowRules[i];
105 device = deviceService.getDevice(f.deviceId());
alshabib219ebaa2014-09-22 15:41:24 -0700106 store.deleteFlowRule(f);
tom7951b232014-10-06 13:35:30 -0700107 if (device != null) {
108 frp = getProvider(device.providerId());
109 frp.removeFlowRule(f);
110 }
alshabib57044ba2014-09-16 15:58:01 -0700111 }
alshabiba68eb962014-09-24 20:34:13 -0700112 }
alshabib57044ba2014-09-16 15:58:01 -0700113
alshabiba68eb962014-09-24 20:34:13 -0700114 @Override
115 public void removeFlowRulesById(ApplicationId id) {
tom9b4030d2014-10-06 10:39:03 -0700116 Iterable<FlowRule> rules = getFlowRulesById(id);
alshabiba68eb962014-09-24 20:34:13 -0700117 FlowRuleProvider frp;
118 Device device;
alshabibbb42cad2014-09-25 11:43:05 -0700119
alshabiba68eb962014-09-24 20:34:13 -0700120 for (FlowRule f : rules) {
121 store.deleteFlowRule(f);
122 device = deviceService.getDevice(f.deviceId());
123 frp = getProvider(device.providerId());
124 frp.removeRulesById(id, f);
125 }
126 }
127
128 @Override
129 public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
alshabib1c319ff2014-10-04 20:29:09 -0700130 return store.getFlowRulesByAppId(id);
alshabib57044ba2014-09-16 15:58:01 -0700131 }
132
133 @Override
134 public void addListener(FlowRuleListener listener) {
135 listenerRegistry.addListener(listener);
136 }
137
138 @Override
139 public void removeListener(FlowRuleListener listener) {
140 listenerRegistry.removeListener(listener);
141 }
142
143 @Override
144 protected FlowRuleProviderService createProviderService(
145 FlowRuleProvider provider) {
146 return new InternalFlowRuleProviderService(provider);
147 }
148
149 private class InternalFlowRuleProviderService
tom9b4030d2014-10-06 10:39:03 -0700150 extends AbstractProviderService<FlowRuleProvider>
151 implements FlowRuleProviderService {
alshabib57044ba2014-09-16 15:58:01 -0700152
153 protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
154 super(provider);
155 }
156
157 @Override
alshabib1c319ff2014-10-04 20:29:09 -0700158 public void flowRemoved(FlowEntry flowEntry) {
159 checkNotNull(flowEntry, FLOW_RULE_NULL);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700160 checkValidity();
alshabib1c319ff2014-10-04 20:29:09 -0700161 FlowEntry stored = store.getFlowEntry(flowEntry);
alshabiba68eb962014-09-24 20:34:13 -0700162 if (stored == null) {
alshabib1c319ff2014-10-04 20:29:09 -0700163 log.info("Rule already evicted from store: {}", flowEntry);
alshabiba68eb962014-09-24 20:34:13 -0700164 return;
165 }
alshabib1c319ff2014-10-04 20:29:09 -0700166 Device device = deviceService.getDevice(flowEntry.deviceId());
alshabiba68eb962014-09-24 20:34:13 -0700167 FlowRuleProvider frp = getProvider(device.providerId());
168 FlowRuleEvent event = null;
169 switch (stored.state()) {
tom9b4030d2014-10-06 10:39:03 -0700170 case ADDED:
171 case PENDING_ADD:
alshabib6eb438a2014-10-01 16:39:37 -0700172 frp.applyFlowRule(stored);
tom9b4030d2014-10-06 10:39:03 -0700173 break;
174 case PENDING_REMOVE:
175 case REMOVED:
176 event = store.removeFlowRule(stored);
177 break;
178 default:
179 break;
alshabib57044ba2014-09-16 15:58:01 -0700180
alshabiba68eb962014-09-24 20:34:13 -0700181 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700182 if (event != null) {
alshabib1c319ff2014-10-04 20:29:09 -0700183 log.debug("Flow {} removed", flowEntry);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700184 post(event);
185 }
alshabib57044ba2014-09-16 15:58:01 -0700186 }
187
alshabibba5ac482014-10-02 17:15:20 -0700188
alshabib1c319ff2014-10-04 20:29:09 -0700189 private void flowMissing(FlowEntry flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700190 checkNotNull(flowRule, FLOW_RULE_NULL);
191 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700192 Device device = deviceService.getDevice(flowRule.deviceId());
193 FlowRuleProvider frp = getProvider(device.providerId());
alshabibbb42cad2014-09-25 11:43:05 -0700194 FlowRuleEvent event = null;
alshabiba68eb962014-09-24 20:34:13 -0700195 switch (flowRule.state()) {
tom9b4030d2014-10-06 10:39:03 -0700196 case PENDING_REMOVE:
197 case REMOVED:
198 event = store.removeFlowRule(flowRule);
199 frp.removeFlowRule(flowRule);
200 break;
201 case ADDED:
202 case PENDING_ADD:
203 frp.applyFlowRule(flowRule);
204 break;
205 default:
206 log.debug("Flow {} has not been installed.", flowRule);
alshabiba68eb962014-09-24 20:34:13 -0700207 }
208
alshabibbb42cad2014-09-25 11:43:05 -0700209 if (event != null) {
210 log.debug("Flow {} removed", flowRule);
211 post(event);
212 }
alshabib57044ba2014-09-16 15:58:01 -0700213
214 }
215
alshabibba5ac482014-10-02 17:15:20 -0700216
217 private void extraneousFlow(FlowRule flowRule) {
alshabib219ebaa2014-09-22 15:41:24 -0700218 checkNotNull(flowRule, FLOW_RULE_NULL);
219 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700220 removeFlowRules(flowRule);
alshabib54ce5892014-09-23 17:50:51 -0700221 log.debug("Flow {} is on switch but not in store.", flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700222 }
223
alshabibba5ac482014-10-02 17:15:20 -0700224
alshabib1c319ff2014-10-04 20:29:09 -0700225 private void flowAdded(FlowEntry flowEntry) {
226 checkNotNull(flowEntry, FLOW_RULE_NULL);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700227 checkValidity();
alshabib57044ba2014-09-16 15:58:01 -0700228
alshabib1c319ff2014-10-04 20:29:09 -0700229 if (checkRuleLiveness(flowEntry, store.getFlowEntry(flowEntry))) {
alshabibba5ac482014-10-02 17:15:20 -0700230
alshabib1c319ff2014-10-04 20:29:09 -0700231 FlowRuleEvent event = store.addOrUpdateFlowRule(flowEntry);
alshabibba5ac482014-10-02 17:15:20 -0700232 if (event == null) {
233 log.debug("No flow store event generated.");
234 } else {
alshabib1c319ff2014-10-04 20:29:09 -0700235 log.debug("Flow {} {}", flowEntry, event.type());
alshabibba5ac482014-10-02 17:15:20 -0700236 post(event);
237 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700238 } else {
alshabib1c319ff2014-10-04 20:29:09 -0700239 removeFlowRules(flowEntry);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700240 }
alshabib219ebaa2014-09-22 15:41:24 -0700241
alshabib57044ba2014-09-16 15:58:01 -0700242 }
243
alshabib1c319ff2014-10-04 20:29:09 -0700244 private boolean checkRuleLiveness(FlowEntry swRule, FlowEntry storedRule) {
245 if (storedRule == null) {
246 return false;
247 }
alshabib85c41972014-10-03 13:48:39 -0700248 long timeout = storedRule.timeout() * 1000;
249 Long currentTime = System.currentTimeMillis();
250 if (storedRule.packets() != swRule.packets()) {
alshabib1c319ff2014-10-04 20:29:09 -0700251 storedRule.setLastSeen();
alshabib85c41972014-10-03 13:48:39 -0700252 return true;
253 }
alshabib85c41972014-10-03 13:48:39 -0700254
alshabib1c319ff2014-10-04 20:29:09 -0700255 if ((currentTime - storedRule.lastSeen()) <= timeout) {
alshabibc274c902014-10-03 14:58:27 -0700256 return true;
257 }
258 return false;
alshabibba5ac482014-10-02 17:15:20 -0700259 }
260
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700261 // Posts the specified event to the local event dispatcher.
262 private void post(FlowRuleEvent event) {
263 if (event != null) {
264 eventDispatcher.post(event);
265 }
266 }
alshabib5c370ff2014-09-18 10:12:14 -0700267
268 @Override
alshabib1c319ff2014-10-04 20:29:09 -0700269 public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowEntry> flowEntries) {
270 List<FlowEntry> storedRules = Lists.newLinkedList(store.getFlowEntries(deviceId));
alshabibbb8b1282014-09-22 17:00:18 -0700271
alshabib1c319ff2014-10-04 20:29:09 -0700272 Iterator<FlowEntry> switchRulesIterator = flowEntries.iterator();
alshabiba7f7ca82014-09-22 11:41:23 -0700273
274 while (switchRulesIterator.hasNext()) {
alshabib1c319ff2014-10-04 20:29:09 -0700275 FlowEntry rule = switchRulesIterator.next();
alshabiba7f7ca82014-09-22 11:41:23 -0700276 if (storedRules.remove(rule)) {
alshabib219ebaa2014-09-22 15:41:24 -0700277 // we both have the rule, let's update some info then.
alshabiba7f7ca82014-09-22 11:41:23 -0700278 flowAdded(rule);
279 } else {
alshabib219ebaa2014-09-22 15:41:24 -0700280 // the device has a rule the store does not have
281 extraneousFlow(rule);
alshabiba7f7ca82014-09-22 11:41:23 -0700282 }
283 }
alshabib1c319ff2014-10-04 20:29:09 -0700284 for (FlowEntry rule : storedRules) {
alshabiba7f7ca82014-09-22 11:41:23 -0700285 // there are rules in the store that aren't on the switch
286 flowMissing(rule);
alshabib54ce5892014-09-23 17:50:51 -0700287
alshabiba7f7ca82014-09-22 11:41:23 -0700288 }
alshabib5c370ff2014-09-18 10:12:14 -0700289 }
alshabib57044ba2014-09-16 15:58:01 -0700290 }
291
tomc78acee2014-09-24 15:16:55 -0700292 // Store delegate to re-post events emitted from the store.
293 private class InternalStoreDelegate implements FlowRuleStoreDelegate {
294 @Override
295 public void notify(FlowRuleEvent event) {
296 eventDispatcher.post(event);
297 }
298 }
alshabib57044ba2014-09-16 15:58:01 -0700299}