blob: 00619b38f213f7118e7591e9d3f72290a433e886 [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;
alshabibba5ac482014-10-02 17:15:20 -07008import java.util.Map;
9import java.util.concurrent.ConcurrentHashMap;
10import java.util.concurrent.atomic.AtomicInteger;
alshabibbb42cad2014-09-25 11:43:05 -070011
alshabib57044ba2014-09-16 15:58:01 -070012import org.apache.felix.scr.annotations.Activate;
13import org.apache.felix.scr.annotations.Component;
14import org.apache.felix.scr.annotations.Deactivate;
15import org.apache.felix.scr.annotations.Reference;
16import org.apache.felix.scr.annotations.ReferenceCardinality;
17import org.apache.felix.scr.annotations.Service;
alshabiba68eb962014-09-24 20:34:13 -070018import org.onlab.onos.ApplicationId;
alshabib57044ba2014-09-16 15:58:01 -070019import org.onlab.onos.event.AbstractListenerRegistry;
20import org.onlab.onos.event.EventDeliveryService;
21import org.onlab.onos.net.Device;
22import org.onlab.onos.net.DeviceId;
23import org.onlab.onos.net.device.DeviceService;
alshabib57044ba2014-09-16 15:58:01 -070024import org.onlab.onos.net.flow.FlowRule;
25import org.onlab.onos.net.flow.FlowRuleEvent;
26import org.onlab.onos.net.flow.FlowRuleListener;
27import org.onlab.onos.net.flow.FlowRuleProvider;
28import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
29import org.onlab.onos.net.flow.FlowRuleProviderService;
30import org.onlab.onos.net.flow.FlowRuleService;
tombe988312014-09-19 18:38:47 -070031import org.onlab.onos.net.flow.FlowRuleStore;
tomc78acee2014-09-24 15:16:55 -070032import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
alshabib57044ba2014-09-16 15:58:01 -070033import org.onlab.onos.net.provider.AbstractProviderRegistry;
34import org.onlab.onos.net.provider.AbstractProviderService;
35import org.slf4j.Logger;
36
alshabibbb42cad2014-09-25 11:43:05 -070037import com.google.common.collect.Lists;
alshabiba7f7ca82014-09-22 11:41:23 -070038
tome4729872014-09-23 00:37:37 -070039/**
40 * Provides implementation of the flow NB & SB APIs.
41 */
alshabib57044ba2014-09-16 15:58:01 -070042@Component(immediate = true)
43@Service
tom202175a2014-09-19 19:00:11 -070044public class FlowRuleManager
alshabiba7f7ca82014-09-22 11:41:23 -070045extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
46implements FlowRuleService, FlowRuleProviderRegistry {
alshabib57044ba2014-09-16 15:58:01 -070047
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070048 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
alshabib57044ba2014-09-16 15:58:01 -070049 private final Logger log = getLogger(getClass());
50
51 private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
alshabiba7f7ca82014-09-22 11:41:23 -070052 listenerRegistry = new AbstractListenerRegistry<>();
alshabib57044ba2014-09-16 15:58:01 -070053
alshabibbb42cad2014-09-25 11:43:05 -070054 private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
tomc78acee2014-09-24 15:16:55 -070055
tombe988312014-09-19 18:38:47 -070056 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
57 protected FlowRuleStore store;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070058
alshabib57044ba2014-09-16 15:58:01 -070059 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070060 protected EventDeliveryService eventDispatcher;
alshabib57044ba2014-09-16 15:58:01 -070061
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070063 protected DeviceService deviceService;
alshabib57044ba2014-09-16 15:58:01 -070064
alshabibba5ac482014-10-02 17:15:20 -070065 private final Map<FlowRule, AtomicInteger> deadRounds = new ConcurrentHashMap<>();
66
alshabib57044ba2014-09-16 15:58:01 -070067 @Activate
68 public void activate() {
tomc78acee2014-09-24 15:16:55 -070069 store.setDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070070 eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
71 log.info("Started");
72 }
73
74 @Deactivate
75 public void deactivate() {
tomc78acee2014-09-24 15:16:55 -070076 store.unsetDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070077 eventDispatcher.removeSink(FlowRuleEvent.class);
78 log.info("Stopped");
79 }
80
81 @Override
Ayaka Koshibed4e53e12014-09-18 14:24:55 -070082 public Iterable<FlowRule> getFlowEntries(DeviceId deviceId) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070083 return store.getFlowEntries(deviceId);
alshabib57044ba2014-09-16 15:58:01 -070084 }
85
86 @Override
alshabib219ebaa2014-09-22 15:41:24 -070087 public void applyFlowRules(FlowRule... flowRules) {
alshabib57044ba2014-09-16 15:58:01 -070088 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -070089 FlowRule f = flowRules[i];
alshabib57044ba2014-09-16 15:58:01 -070090 final Device device = deviceService.getDevice(f.deviceId());
91 final FlowRuleProvider frp = getProvider(device.providerId());
alshabibba5ac482014-10-02 17:15:20 -070092 deadRounds.put(f, new AtomicInteger(0));
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());
106 frp = getProvider(device.providerId());
alshabibba5ac482014-10-02 17:15:20 -0700107 deadRounds.remove(f);
alshabib219ebaa2014-09-22 15:41:24 -0700108 store.deleteFlowRule(f);
alshabib57044ba2014-09-16 15:58:01 -0700109 frp.removeFlowRule(f);
110 }
alshabiba68eb962014-09-24 20:34:13 -0700111 }
alshabib57044ba2014-09-16 15:58:01 -0700112
alshabiba68eb962014-09-24 20:34:13 -0700113 @Override
114 public void removeFlowRulesById(ApplicationId id) {
115 Iterable<FlowRule> rules = getFlowRulesById(id);
116 FlowRuleProvider frp;
117 Device device;
alshabibbb42cad2014-09-25 11:43:05 -0700118
alshabiba68eb962014-09-24 20:34:13 -0700119 for (FlowRule f : rules) {
120 store.deleteFlowRule(f);
121 device = deviceService.getDevice(f.deviceId());
122 frp = getProvider(device.providerId());
123 frp.removeRulesById(id, f);
124 }
125 }
126
127 @Override
128 public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
129 return store.getFlowEntriesByAppId(id);
alshabib57044ba2014-09-16 15:58:01 -0700130 }
131
132 @Override
133 public void addListener(FlowRuleListener listener) {
134 listenerRegistry.addListener(listener);
135 }
136
137 @Override
138 public void removeListener(FlowRuleListener listener) {
139 listenerRegistry.removeListener(listener);
140 }
141
142 @Override
143 protected FlowRuleProviderService createProviderService(
144 FlowRuleProvider provider) {
145 return new InternalFlowRuleProviderService(provider);
146 }
147
148 private class InternalFlowRuleProviderService
alshabiba7f7ca82014-09-22 11:41:23 -0700149 extends AbstractProviderService<FlowRuleProvider>
150 implements FlowRuleProviderService {
alshabib57044ba2014-09-16 15:58:01 -0700151
152 protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
153 super(provider);
154 }
155
156 @Override
157 public void flowRemoved(FlowRule flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700158 checkNotNull(flowRule, FLOW_RULE_NULL);
159 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700160 FlowRule stored = store.getFlowRule(flowRule);
161 if (stored == null) {
162 log.debug("Rule already evicted from store: {}", flowRule);
163 return;
164 }
165 Device device = deviceService.getDevice(flowRule.deviceId());
166 FlowRuleProvider frp = getProvider(device.providerId());
167 FlowRuleEvent event = null;
168 switch (stored.state()) {
169 case ADDED:
170 case PENDING_ADD:
alshabib6eb438a2014-10-01 16:39:37 -0700171 frp.applyFlowRule(stored);
alshabiba68eb962014-09-24 20:34:13 -0700172 break;
173 case PENDING_REMOVE:
174 case REMOVED:
175 event = store.removeFlowRule(flowRule);
176 break;
177 default:
178 break;
alshabib57044ba2014-09-16 15:58:01 -0700179
alshabiba68eb962014-09-24 20:34:13 -0700180 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700181 if (event != null) {
182 log.debug("Flow {} removed", flowRule);
183 post(event);
184 }
alshabib57044ba2014-09-16 15:58:01 -0700185 }
186
alshabibba5ac482014-10-02 17:15:20 -0700187
188 private void flowMissing(FlowRule flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700189 checkNotNull(flowRule, FLOW_RULE_NULL);
190 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700191 Device device = deviceService.getDevice(flowRule.deviceId());
192 FlowRuleProvider frp = getProvider(device.providerId());
alshabibbb42cad2014-09-25 11:43:05 -0700193 FlowRuleEvent event = null;
alshabiba68eb962014-09-24 20:34:13 -0700194 switch (flowRule.state()) {
195 case PENDING_REMOVE:
196 case REMOVED:
alshabibbb42cad2014-09-25 11:43:05 -0700197 event = store.removeFlowRule(flowRule);
alshabiba68eb962014-09-24 20:34:13 -0700198 frp.removeFlowRule(flowRule);
199 break;
200 case ADDED:
201 case PENDING_ADD:
202 frp.applyFlowRule(flowRule);
203 break;
204 default:
205 log.debug("Flow {} has not been installed.", flowRule);
206 }
207
alshabibbb42cad2014-09-25 11:43:05 -0700208 if (event != null) {
209 log.debug("Flow {} removed", flowRule);
210 post(event);
211 }
alshabib57044ba2014-09-16 15:58:01 -0700212
213 }
214
alshabibba5ac482014-10-02 17:15:20 -0700215
216 private void extraneousFlow(FlowRule flowRule) {
alshabib219ebaa2014-09-22 15:41:24 -0700217 checkNotNull(flowRule, FLOW_RULE_NULL);
218 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700219 removeFlowRules(flowRule);
alshabib54ce5892014-09-23 17:50:51 -0700220 log.debug("Flow {} is on switch but not in store.", flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700221 }
222
alshabibba5ac482014-10-02 17:15:20 -0700223
224 private void flowAdded(FlowRule flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700225 checkNotNull(flowRule, FLOW_RULE_NULL);
226 checkValidity();
alshabib57044ba2014-09-16 15:58:01 -0700227
alshabibba5ac482014-10-02 17:15:20 -0700228 if (deadRounds.containsKey(flowRule) &&
229 checkRuleLiveness(flowRule, store.getFlowRule(flowRule))) {
230
231 FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule);
232 if (event == null) {
233 log.debug("No flow store event generated.");
234 } else {
235 log.debug("Flow {} {}", flowRule, event.type());
236 post(event);
237 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700238 } else {
alshabibba5ac482014-10-02 17:15:20 -0700239 removeFlowRules(flowRule);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700240 }
alshabib219ebaa2014-09-22 15:41:24 -0700241
alshabib57044ba2014-09-16 15:58:01 -0700242 }
243
alshabibba5ac482014-10-02 17:15:20 -0700244 private boolean checkRuleLiveness(FlowRule swRule, FlowRule storedRule) {
245 int timeout = storedRule.timeout();
246 if (storedRule.packets() != swRule.packets()) {
247 deadRounds.get(swRule).set(0);
248 return true;
249 }
250
251 return (deadRounds.get(swRule).getAndIncrement() *
252 FlowRuleProvider.POLL_INTERVAL) <= timeout;
253
254 }
255
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700256 // Posts the specified event to the local event dispatcher.
257 private void post(FlowRuleEvent event) {
258 if (event != null) {
259 eventDispatcher.post(event);
260 }
261 }
alshabib5c370ff2014-09-18 10:12:14 -0700262
263 @Override
alshabiba7f7ca82014-09-22 11:41:23 -0700264 public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowRule> flowEntries) {
265 List<FlowRule> storedRules = Lists.newLinkedList(store.getFlowEntries(deviceId));
alshabibbb8b1282014-09-22 17:00:18 -0700266
267 Iterator<FlowRule> switchRulesIterator = flowEntries.iterator();
alshabiba7f7ca82014-09-22 11:41:23 -0700268
269 while (switchRulesIterator.hasNext()) {
270 FlowRule rule = switchRulesIterator.next();
271 if (storedRules.remove(rule)) {
alshabib219ebaa2014-09-22 15:41:24 -0700272 // we both have the rule, let's update some info then.
alshabiba7f7ca82014-09-22 11:41:23 -0700273 flowAdded(rule);
274 } else {
alshabib219ebaa2014-09-22 15:41:24 -0700275 // the device has a rule the store does not have
276 extraneousFlow(rule);
alshabiba7f7ca82014-09-22 11:41:23 -0700277 }
278 }
279 for (FlowRule rule : storedRules) {
280 // there are rules in the store that aren't on the switch
281 flowMissing(rule);
alshabib54ce5892014-09-23 17:50:51 -0700282
alshabiba7f7ca82014-09-22 11:41:23 -0700283 }
alshabib5c370ff2014-09-18 10:12:14 -0700284 }
alshabib57044ba2014-09-16 15:58:01 -0700285 }
286
tomc78acee2014-09-24 15:16:55 -0700287 // Store delegate to re-post events emitted from the store.
288 private class InternalStoreDelegate implements FlowRuleStoreDelegate {
289 @Override
290 public void notify(FlowRuleEvent event) {
291 eventDispatcher.post(event);
292 }
293 }
alshabib57044ba2014-09-16 15:58:01 -0700294}