blob: ae6a81d65b5811dfda10f348ba4d1d9749bb9f6d [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;
alshabibbb42cad2014-09-25 11:43:05 -070010
alshabib57044ba2014-09-16 15:58:01 -070011import org.apache.felix.scr.annotations.Activate;
12import org.apache.felix.scr.annotations.Component;
13import org.apache.felix.scr.annotations.Deactivate;
14import org.apache.felix.scr.annotations.Reference;
15import org.apache.felix.scr.annotations.ReferenceCardinality;
16import org.apache.felix.scr.annotations.Service;
alshabiba68eb962014-09-24 20:34:13 -070017import org.onlab.onos.ApplicationId;
alshabib57044ba2014-09-16 15:58:01 -070018import org.onlab.onos.event.AbstractListenerRegistry;
19import org.onlab.onos.event.EventDeliveryService;
20import org.onlab.onos.net.Device;
21import org.onlab.onos.net.DeviceId;
22import org.onlab.onos.net.device.DeviceService;
alshabib57044ba2014-09-16 15:58:01 -070023import org.onlab.onos.net.flow.FlowRule;
24import org.onlab.onos.net.flow.FlowRuleEvent;
25import org.onlab.onos.net.flow.FlowRuleListener;
26import org.onlab.onos.net.flow.FlowRuleProvider;
27import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
28import org.onlab.onos.net.flow.FlowRuleProviderService;
29import org.onlab.onos.net.flow.FlowRuleService;
tombe988312014-09-19 18:38:47 -070030import org.onlab.onos.net.flow.FlowRuleStore;
tomc78acee2014-09-24 15:16:55 -070031import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
alshabib57044ba2014-09-16 15:58:01 -070032import org.onlab.onos.net.provider.AbstractProviderRegistry;
33import org.onlab.onos.net.provider.AbstractProviderService;
34import org.slf4j.Logger;
35
alshabibbb42cad2014-09-25 11:43:05 -070036import com.google.common.collect.Lists;
alshabiba7f7ca82014-09-22 11:41:23 -070037
tome4729872014-09-23 00:37:37 -070038/**
39 * Provides implementation of the flow NB & SB APIs.
40 */
alshabib57044ba2014-09-16 15:58:01 -070041@Component(immediate = true)
42@Service
tom202175a2014-09-19 19:00:11 -070043public class FlowRuleManager
alshabiba7f7ca82014-09-22 11:41:23 -070044extends AbstractProviderRegistry<FlowRuleProvider, FlowRuleProviderService>
45implements FlowRuleService, FlowRuleProviderRegistry {
alshabib57044ba2014-09-16 15:58:01 -070046
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070047 public static final String FLOW_RULE_NULL = "FlowRule cannot be null";
alshabib57044ba2014-09-16 15:58:01 -070048 private final Logger log = getLogger(getClass());
49
50 private final AbstractListenerRegistry<FlowRuleEvent, FlowRuleListener>
alshabiba7f7ca82014-09-22 11:41:23 -070051 listenerRegistry = new AbstractListenerRegistry<>();
alshabib57044ba2014-09-16 15:58:01 -070052
alshabibbb42cad2014-09-25 11:43:05 -070053 private final FlowRuleStoreDelegate delegate = new InternalStoreDelegate();
tomc78acee2014-09-24 15:16:55 -070054
tombe988312014-09-19 18:38:47 -070055 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected FlowRuleStore store;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070057
alshabib57044ba2014-09-16 15:58:01 -070058 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070059 protected EventDeliveryService eventDispatcher;
alshabib57044ba2014-09-16 15:58:01 -070060
61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070062 protected DeviceService deviceService;
alshabib57044ba2014-09-16 15:58:01 -070063
alshabib85c41972014-10-03 13:48:39 -070064 private final Map<FlowRule, Long> idleTime = new ConcurrentHashMap<>();
alshabibba5ac482014-10-02 17:15:20 -070065
alshabib57044ba2014-09-16 15:58:01 -070066 @Activate
67 public void activate() {
tomc78acee2014-09-24 15:16:55 -070068 store.setDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070069 eventDispatcher.addSink(FlowRuleEvent.class, listenerRegistry);
70 log.info("Started");
71 }
72
73 @Deactivate
74 public void deactivate() {
tomc78acee2014-09-24 15:16:55 -070075 store.unsetDelegate(delegate);
alshabib57044ba2014-09-16 15:58:01 -070076 eventDispatcher.removeSink(FlowRuleEvent.class);
77 log.info("Stopped");
78 }
79
80 @Override
Ayaka Koshibed4e53e12014-09-18 14:24:55 -070081 public Iterable<FlowRule> getFlowEntries(DeviceId deviceId) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070082 return store.getFlowEntries(deviceId);
alshabib57044ba2014-09-16 15:58:01 -070083 }
84
85 @Override
alshabib219ebaa2014-09-22 15:41:24 -070086 public void applyFlowRules(FlowRule... flowRules) {
alshabib57044ba2014-09-16 15:58:01 -070087 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -070088 FlowRule f = flowRules[i];
alshabib57044ba2014-09-16 15:58:01 -070089 final Device device = deviceService.getDevice(f.deviceId());
90 final FlowRuleProvider frp = getProvider(device.providerId());
alshabib85c41972014-10-03 13:48:39 -070091 idleTime.put(f, System.currentTimeMillis());
alshabib219ebaa2014-09-22 15:41:24 -070092 store.storeFlowRule(f);
alshabib57044ba2014-09-16 15:58:01 -070093 frp.applyFlowRule(f);
94 }
alshabib57044ba2014-09-16 15:58:01 -070095 }
96
97 @Override
98 public void removeFlowRules(FlowRule... flowRules) {
alshabibbb8b1282014-09-22 17:00:18 -070099 FlowRule f;
alshabiba68eb962014-09-24 20:34:13 -0700100 FlowRuleProvider frp;
101 Device device;
alshabib57044ba2014-09-16 15:58:01 -0700102 for (int i = 0; i < flowRules.length; i++) {
alshabiba68eb962014-09-24 20:34:13 -0700103 f = flowRules[i];
104 device = deviceService.getDevice(f.deviceId());
105 frp = getProvider(device.providerId());
alshabib85c41972014-10-03 13:48:39 -0700106 idleTime.remove(f);
alshabib219ebaa2014-09-22 15:41:24 -0700107 store.deleteFlowRule(f);
alshabib57044ba2014-09-16 15:58:01 -0700108 frp.removeFlowRule(f);
109 }
alshabiba68eb962014-09-24 20:34:13 -0700110 }
alshabib57044ba2014-09-16 15:58:01 -0700111
alshabiba68eb962014-09-24 20:34:13 -0700112 @Override
113 public void removeFlowRulesById(ApplicationId id) {
114 Iterable<FlowRule> rules = getFlowRulesById(id);
115 FlowRuleProvider frp;
116 Device device;
alshabibbb42cad2014-09-25 11:43:05 -0700117
alshabiba68eb962014-09-24 20:34:13 -0700118 for (FlowRule f : rules) {
119 store.deleteFlowRule(f);
120 device = deviceService.getDevice(f.deviceId());
121 frp = getProvider(device.providerId());
122 frp.removeRulesById(id, f);
123 }
124 }
125
126 @Override
127 public Iterable<FlowRule> getFlowRulesById(ApplicationId id) {
128 return store.getFlowEntriesByAppId(id);
alshabib57044ba2014-09-16 15:58:01 -0700129 }
130
131 @Override
132 public void addListener(FlowRuleListener listener) {
133 listenerRegistry.addListener(listener);
134 }
135
136 @Override
137 public void removeListener(FlowRuleListener listener) {
138 listenerRegistry.removeListener(listener);
139 }
140
141 @Override
142 protected FlowRuleProviderService createProviderService(
143 FlowRuleProvider provider) {
144 return new InternalFlowRuleProviderService(provider);
145 }
146
147 private class InternalFlowRuleProviderService
alshabiba7f7ca82014-09-22 11:41:23 -0700148 extends AbstractProviderService<FlowRuleProvider>
149 implements FlowRuleProviderService {
alshabib57044ba2014-09-16 15:58:01 -0700150
151 protected InternalFlowRuleProviderService(FlowRuleProvider provider) {
152 super(provider);
153 }
154
155 @Override
156 public void flowRemoved(FlowRule flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700157 checkNotNull(flowRule, FLOW_RULE_NULL);
158 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700159 FlowRule stored = store.getFlowRule(flowRule);
160 if (stored == null) {
161 log.debug("Rule already evicted from store: {}", flowRule);
162 return;
163 }
164 Device device = deviceService.getDevice(flowRule.deviceId());
165 FlowRuleProvider frp = getProvider(device.providerId());
166 FlowRuleEvent event = null;
167 switch (stored.state()) {
168 case ADDED:
169 case PENDING_ADD:
alshabib6eb438a2014-10-01 16:39:37 -0700170 frp.applyFlowRule(stored);
alshabiba68eb962014-09-24 20:34:13 -0700171 break;
172 case PENDING_REMOVE:
173 case REMOVED:
174 event = store.removeFlowRule(flowRule);
175 break;
176 default:
177 break;
alshabib57044ba2014-09-16 15:58:01 -0700178
alshabiba68eb962014-09-24 20:34:13 -0700179 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700180 if (event != null) {
181 log.debug("Flow {} removed", flowRule);
182 post(event);
183 }
alshabib57044ba2014-09-16 15:58:01 -0700184 }
185
alshabibba5ac482014-10-02 17:15:20 -0700186
187 private void flowMissing(FlowRule flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700188 checkNotNull(flowRule, FLOW_RULE_NULL);
189 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700190 Device device = deviceService.getDevice(flowRule.deviceId());
191 FlowRuleProvider frp = getProvider(device.providerId());
alshabibbb42cad2014-09-25 11:43:05 -0700192 FlowRuleEvent event = null;
alshabiba68eb962014-09-24 20:34:13 -0700193 switch (flowRule.state()) {
194 case PENDING_REMOVE:
195 case REMOVED:
alshabibbb42cad2014-09-25 11:43:05 -0700196 event = store.removeFlowRule(flowRule);
alshabiba68eb962014-09-24 20:34:13 -0700197 frp.removeFlowRule(flowRule);
198 break;
199 case ADDED:
200 case PENDING_ADD:
201 frp.applyFlowRule(flowRule);
202 break;
203 default:
204 log.debug("Flow {} has not been installed.", flowRule);
205 }
206
alshabibbb42cad2014-09-25 11:43:05 -0700207 if (event != null) {
208 log.debug("Flow {} removed", flowRule);
209 post(event);
210 }
alshabib57044ba2014-09-16 15:58:01 -0700211
212 }
213
alshabibba5ac482014-10-02 17:15:20 -0700214
215 private void extraneousFlow(FlowRule flowRule) {
alshabib219ebaa2014-09-22 15:41:24 -0700216 checkNotNull(flowRule, FLOW_RULE_NULL);
217 checkValidity();
alshabiba68eb962014-09-24 20:34:13 -0700218 removeFlowRules(flowRule);
alshabib54ce5892014-09-23 17:50:51 -0700219 log.debug("Flow {} is on switch but not in store.", flowRule);
alshabib219ebaa2014-09-22 15:41:24 -0700220 }
221
alshabibba5ac482014-10-02 17:15:20 -0700222
223 private void flowAdded(FlowRule flowRule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700224 checkNotNull(flowRule, FLOW_RULE_NULL);
225 checkValidity();
alshabib57044ba2014-09-16 15:58:01 -0700226
alshabib85c41972014-10-03 13:48:39 -0700227 if (idleTime.containsKey(flowRule) &&
alshabibba5ac482014-10-02 17:15:20 -0700228 checkRuleLiveness(flowRule, store.getFlowRule(flowRule))) {
229
230 FlowRuleEvent event = store.addOrUpdateFlowRule(flowRule);
231 if (event == null) {
232 log.debug("No flow store event generated.");
233 } else {
234 log.debug("Flow {} {}", flowRule, event.type());
235 post(event);
236 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700237 } else {
alshabibba5ac482014-10-02 17:15:20 -0700238 removeFlowRules(flowRule);
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700239 }
alshabib219ebaa2014-09-22 15:41:24 -0700240
alshabib57044ba2014-09-16 15:58:01 -0700241 }
242
alshabibba5ac482014-10-02 17:15:20 -0700243 private boolean checkRuleLiveness(FlowRule swRule, FlowRule storedRule) {
alshabib85c41972014-10-03 13:48:39 -0700244 long timeout = storedRule.timeout() * 1000;
245 Long currentTime = System.currentTimeMillis();
246 if (storedRule.packets() != swRule.packets()) {
247 idleTime.put(swRule, currentTime);
248 return true;
249 }
250 return (currentTime - idleTime.get(swRule)) <= timeout;
251
alshabibba5ac482014-10-02 17:15:20 -0700252 }
253
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700254 // Posts the specified event to the local event dispatcher.
255 private void post(FlowRuleEvent event) {
256 if (event != null) {
257 eventDispatcher.post(event);
258 }
259 }
alshabib5c370ff2014-09-18 10:12:14 -0700260
261 @Override
alshabiba7f7ca82014-09-22 11:41:23 -0700262 public void pushFlowMetrics(DeviceId deviceId, Iterable<FlowRule> flowEntries) {
263 List<FlowRule> storedRules = Lists.newLinkedList(store.getFlowEntries(deviceId));
alshabibbb8b1282014-09-22 17:00:18 -0700264
265 Iterator<FlowRule> switchRulesIterator = flowEntries.iterator();
alshabiba7f7ca82014-09-22 11:41:23 -0700266
267 while (switchRulesIterator.hasNext()) {
268 FlowRule rule = switchRulesIterator.next();
269 if (storedRules.remove(rule)) {
alshabib219ebaa2014-09-22 15:41:24 -0700270 // we both have the rule, let's update some info then.
alshabiba7f7ca82014-09-22 11:41:23 -0700271 flowAdded(rule);
272 } else {
alshabib219ebaa2014-09-22 15:41:24 -0700273 // the device has a rule the store does not have
274 extraneousFlow(rule);
alshabiba7f7ca82014-09-22 11:41:23 -0700275 }
276 }
277 for (FlowRule rule : storedRules) {
278 // there are rules in the store that aren't on the switch
279 flowMissing(rule);
alshabib54ce5892014-09-23 17:50:51 -0700280
alshabiba7f7ca82014-09-22 11:41:23 -0700281 }
alshabib5c370ff2014-09-18 10:12:14 -0700282 }
alshabib57044ba2014-09-16 15:58:01 -0700283 }
284
tomc78acee2014-09-24 15:16:55 -0700285 // Store delegate to re-post events emitted from the store.
286 private class InternalStoreDelegate implements FlowRuleStoreDelegate {
287 @Override
288 public void notify(FlowRuleEvent event) {
289 eventDispatcher.post(event);
290 }
291 }
alshabib57044ba2014-09-16 15:58:01 -0700292}