blob: b6ebda40bb43a4e9529f0f7875068f1ac3087a72 [file] [log] [blame]
tomea961ff2014-10-01 12:45:15 -07001package org.onlab.onos.store.trivial.impl;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -07002
alshabib219ebaa2014-09-22 15:41:24 -07003import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
4import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI605347c2014-10-17 21:05:23 -07005import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
6import static java.util.Collections.unmodifiableCollection;
alshabib219ebaa2014-09-22 15:41:24 -07007
Yuta HIGUCHI605347c2014-10-17 21:05:23 -07008import java.util.HashSet;
9import java.util.Set;
10import java.util.concurrent.ConcurrentHashMap;
11import java.util.concurrent.ConcurrentMap;
alshabiba68eb962014-09-24 20:34:13 -070012
tom85c612b2014-09-19 19:25:47 -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.Service;
alshabiba68eb962014-09-24 20:34:13 -070017import org.onlab.onos.ApplicationId;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070018import org.onlab.onos.net.DeviceId;
alshabib1c319ff2014-10-04 20:29:09 -070019import org.onlab.onos.net.flow.DefaultFlowEntry;
20import org.onlab.onos.net.flow.FlowEntry;
21import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070022import org.onlab.onos.net.flow.FlowId;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070023import org.onlab.onos.net.flow.FlowRule;
24import org.onlab.onos.net.flow.FlowRuleEvent;
alshabib219ebaa2014-09-22 15:41:24 -070025import org.onlab.onos.net.flow.FlowRuleEvent.Type;
tombe988312014-09-19 18:38:47 -070026import org.onlab.onos.net.flow.FlowRuleStore;
tomc78acee2014-09-24 15:16:55 -070027import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
28import org.onlab.onos.store.AbstractStore;
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070029import org.onlab.util.NewConcurrentHashMap;
tom85c612b2014-09-19 19:25:47 -070030import org.slf4j.Logger;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070031
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070032/**
33 * Manages inventory of flow rules using trivial in-memory implementation.
34 */
tom85c612b2014-09-19 19:25:47 -070035@Component(immediate = true)
36@Service
tomc78acee2014-09-24 15:16:55 -070037public class SimpleFlowRuleStore
38 extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate>
39 implements FlowRuleStore {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070040
tom85c612b2014-09-19 19:25:47 -070041 private final Logger log = getLogger(getClass());
42
alshabiba68eb962014-09-24 20:34:13 -070043
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070044 // inner Map is Device flow table
45 // Assumption: FlowId cannot have synonyms
46 private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, FlowEntry>>
47 flowEntries = new ConcurrentHashMap<>();
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070048
tom85c612b2014-09-19 19:25:47 -070049 @Activate
50 public void activate() {
51 log.info("Started");
52 }
53
54 @Deactivate
55 public void deactivate() {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070056 flowEntries.clear();
tom85c612b2014-09-19 19:25:47 -070057 log.info("Stopped");
58 }
59
alshabiba68eb962014-09-24 20:34:13 -070060
tombe988312014-09-19 18:38:47 -070061 @Override
tom9b4030d2014-10-06 10:39:03 -070062 public int getFlowRuleCount() {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070063 int sum = 0;
64 for (ConcurrentMap<FlowId, FlowEntry> ft : flowEntries.values()) {
65 sum += ft.size();
66 }
67 return sum;
68 }
69
70 private static NewConcurrentHashMap<FlowId, FlowEntry> lazyEmptyFlowTable() {
71 return NewConcurrentHashMap.<FlowId, FlowEntry>ifNeeded();
72 }
73
74 /**
75 * Returns the flow table for specified device.
76 *
77 * @param deviceId identifier of the device
78 * @return Map representing Flow Table of given device.
79 */
80 private ConcurrentMap<FlowId, FlowEntry> getFlowTable(DeviceId deviceId) {
81 return createIfAbsentUnchecked(flowEntries,
82 deviceId, lazyEmptyFlowTable());
83 }
84
85 private FlowEntry getFlowEntry(DeviceId deviceId, FlowId flowId) {
86 return getFlowTable(deviceId).get(flowId);
tom9b4030d2014-10-06 10:39:03 -070087 }
88
89 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070090 public FlowEntry getFlowEntry(FlowRule rule) {
91 return getFlowEntry(rule.deviceId(), rule.id());
92 }
93
94 @Override
95 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
96 return unmodifiableCollection(getFlowTable(deviceId).values());
97 }
98
99 @Override
100 public Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
101
102 Set<FlowRule> rules = new HashSet<>();
103 for (DeviceId did : flowEntries.keySet()) {
104 ConcurrentMap<FlowId, FlowEntry> ft = getFlowTable(did);
105 for (FlowEntry fe : ft.values()) {
106 if (fe.appId() == appId.id()) {
107 rules.add(fe);
108 }
alshabiba68eb962014-09-24 20:34:13 -0700109 }
110 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700111 return rules;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700112 }
113
tombe988312014-09-19 18:38:47 -0700114 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700115 public void storeFlowRule(FlowRule rule) {
116 final boolean added = storeFlowRuleInternal(rule);
alshabib219ebaa2014-09-22 15:41:24 -0700117 }
118
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700119 private boolean storeFlowRuleInternal(FlowRule rule) {
alshabib1c319ff2014-10-04 20:29:09 -0700120 FlowEntry f = new DefaultFlowEntry(rule);
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700121 final DeviceId did = f.deviceId();
122 final FlowId fid = f.id();
123 FlowEntry existing = getFlowTable(did).putIfAbsent(fid, f);
124 if (existing != null) {
125 // was already there? ignore
126 return false;
alshabiba68eb962014-09-24 20:34:13 -0700127 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700128 // new flow rule added
129 // TODO: notify through delegate about remote event?
130 return true;
alshabiba68eb962014-09-24 20:34:13 -0700131 }
132
133 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700134 public void deleteFlowRule(FlowRule rule) {
135
136 FlowEntry entry = getFlowEntry(rule.deviceId(), rule.id());
alshabib1c319ff2014-10-04 20:29:09 -0700137 if (entry == null) {
Yuta HIGUCHI58e40432014-10-19 15:43:41 -0700138 //log.warn("Cannot find rule {}", rule);
alshabib1c319ff2014-10-04 20:29:09 -0700139 return;
alshabib219ebaa2014-09-22 15:41:24 -0700140 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700141 synchronized (entry) {
142 entry.setState(FlowEntryState.PENDING_REMOVE);
143 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700144 }
145
tombe988312014-09-19 18:38:47 -0700146 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700147 public FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700148 // check if this new rule is an update to an existing entry
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700149 FlowEntry stored = getFlowEntry(rule.deviceId(), rule.id());
alshabibba5ac482014-10-02 17:15:20 -0700150 if (stored != null) {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700151 synchronized (stored) {
152 stored.setBytes(rule.bytes());
153 stored.setLife(rule.life());
154 stored.setPackets(rule.packets());
155 if (stored.state() == FlowEntryState.PENDING_ADD) {
156 stored.setState(FlowEntryState.ADDED);
157 // TODO: Do we need to change `rule` state?
158 return new FlowRuleEvent(Type.RULE_ADDED, rule);
159 }
160 return new FlowRuleEvent(Type.RULE_UPDATED, rule);
alshabibba5ac482014-10-02 17:15:20 -0700161 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700162 }
alshabib219ebaa2014-09-22 15:41:24 -0700163
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700164 // should not reach here
165 // storeFlowRule was expected to be called
166 log.error("FlowRule was not found in store {} to update", rule);
167
alshabib8ca53902014-10-07 13:11:17 -0700168 //flowEntries.put(did, rule);
alshabibba5ac482014-10-02 17:15:20 -0700169 return null;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700170 }
171
tombe988312014-09-19 18:38:47 -0700172 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700173 public FlowRuleEvent removeFlowRule(FlowEntry rule) {
alshabib1c319ff2014-10-04 20:29:09 -0700174 // This is where one could mark a rule as removed and still keep it in the store.
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700175 final DeviceId did = rule.deviceId();
176
177 ConcurrentMap<FlowId, FlowEntry> ft = getFlowTable(did);
178 if (ft.remove(rule.id(), rule)) {
alshabiba68eb962014-09-24 20:34:13 -0700179 return new FlowRuleEvent(RULE_REMOVED, rule);
180 } else {
181 return null;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700182 }
183 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700184}