blob: 8ca2ca032f69175b8c0cedbb911252c1282df2ef [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 HIGUCHIf6f50a62014-10-19 15:58:49 -07008import java.util.Collection;
Yuta HIGUCHI605347c2014-10-17 21:05:23 -07009import java.util.HashSet;
10import java.util.Set;
11import java.util.concurrent.ConcurrentHashMap;
12import java.util.concurrent.ConcurrentMap;
alshabiba68eb962014-09-24 20:34:13 -070013
tom85c612b2014-09-19 19:25:47 -070014import org.apache.felix.scr.annotations.Activate;
15import org.apache.felix.scr.annotations.Component;
16import org.apache.felix.scr.annotations.Deactivate;
17import org.apache.felix.scr.annotations.Service;
alshabiba68eb962014-09-24 20:34:13 -070018import org.onlab.onos.ApplicationId;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070019import org.onlab.onos.net.DeviceId;
alshabib1c319ff2014-10-04 20:29:09 -070020import org.onlab.onos.net.flow.DefaultFlowEntry;
21import org.onlab.onos.net.flow.FlowEntry;
22import org.onlab.onos.net.flow.FlowEntry.FlowEntryState;
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070023import org.onlab.onos.net.flow.FlowId;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070024import org.onlab.onos.net.flow.FlowRule;
25import org.onlab.onos.net.flow.FlowRuleEvent;
alshabib219ebaa2014-09-22 15:41:24 -070026import org.onlab.onos.net.flow.FlowRuleEvent.Type;
tombe988312014-09-19 18:38:47 -070027import org.onlab.onos.net.flow.FlowRuleStore;
tomc78acee2014-09-24 15:16:55 -070028import org.onlab.onos.net.flow.FlowRuleStoreDelegate;
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070029import org.onlab.onos.net.flow.StoredFlowEntry;
tomc78acee2014-09-24 15:16:55 -070030import org.onlab.onos.store.AbstractStore;
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070031import org.onlab.util.NewConcurrentHashMap;
tom85c612b2014-09-19 19:25:47 -070032import org.slf4j.Logger;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070033
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070034/**
35 * Manages inventory of flow rules using trivial in-memory implementation.
36 */
tom85c612b2014-09-19 19:25:47 -070037@Component(immediate = true)
38@Service
tomc78acee2014-09-24 15:16:55 -070039public class SimpleFlowRuleStore
40 extends AbstractStore<FlowRuleEvent, FlowRuleStoreDelegate>
41 implements FlowRuleStore {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070042
tom85c612b2014-09-19 19:25:47 -070043 private final Logger log = getLogger(getClass());
44
alshabiba68eb962014-09-24 20:34:13 -070045
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070046 // inner Map is Device flow table
47 // Assumption: FlowId cannot have synonyms
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070048 private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, StoredFlowEntry>>
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070049 flowEntries = new ConcurrentHashMap<>();
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -070050
tom85c612b2014-09-19 19:25:47 -070051 @Activate
52 public void activate() {
53 log.info("Started");
54 }
55
56 @Deactivate
57 public void deactivate() {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070058 flowEntries.clear();
tom85c612b2014-09-19 19:25:47 -070059 log.info("Stopped");
60 }
61
alshabiba68eb962014-09-24 20:34:13 -070062
tombe988312014-09-19 18:38:47 -070063 @Override
tom9b4030d2014-10-06 10:39:03 -070064 public int getFlowRuleCount() {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070065 int sum = 0;
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070066 for (ConcurrentMap<FlowId, StoredFlowEntry> ft : flowEntries.values()) {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070067 sum += ft.size();
68 }
69 return sum;
70 }
71
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070072 private static NewConcurrentHashMap<FlowId, StoredFlowEntry> lazyEmptyFlowTable() {
73 return NewConcurrentHashMap.<FlowId, StoredFlowEntry>ifNeeded();
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070074 }
75
76 /**
77 * Returns the flow table for specified device.
78 *
79 * @param deviceId identifier of the device
80 * @return Map representing Flow Table of given device.
81 */
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070082 private ConcurrentMap<FlowId, StoredFlowEntry> getFlowTable(DeviceId deviceId) {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070083 return createIfAbsentUnchecked(flowEntries,
84 deviceId, lazyEmptyFlowTable());
85 }
86
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070087 private StoredFlowEntry getFlowEntry(DeviceId deviceId, FlowId flowId) {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070088 return getFlowTable(deviceId).get(flowId);
tom9b4030d2014-10-06 10:39:03 -070089 }
90
91 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -070092 public FlowEntry getFlowEntry(FlowRule rule) {
93 return getFlowEntry(rule.deviceId(), rule.id());
94 }
95
96 @Override
97 public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -070098 return unmodifiableCollection((Collection<? extends FlowEntry>)
99 getFlowTable(deviceId).values());
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700100 }
101
102 @Override
103 public Iterable<FlowRule> getFlowRulesByAppId(ApplicationId appId) {
104
105 Set<FlowRule> rules = new HashSet<>();
106 for (DeviceId did : flowEntries.keySet()) {
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -0700107 ConcurrentMap<FlowId, StoredFlowEntry> ft = getFlowTable(did);
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700108 for (FlowEntry fe : ft.values()) {
109 if (fe.appId() == appId.id()) {
110 rules.add(fe);
111 }
alshabiba68eb962014-09-24 20:34:13 -0700112 }
113 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700114 return rules;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700115 }
116
tombe988312014-09-19 18:38:47 -0700117 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700118 public void storeFlowRule(FlowRule rule) {
119 final boolean added = storeFlowRuleInternal(rule);
alshabib219ebaa2014-09-22 15:41:24 -0700120 }
121
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700122 private boolean storeFlowRuleInternal(FlowRule rule) {
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -0700123 StoredFlowEntry f = new DefaultFlowEntry(rule);
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700124 final DeviceId did = f.deviceId();
125 final FlowId fid = f.id();
126 FlowEntry existing = getFlowTable(did).putIfAbsent(fid, f);
127 if (existing != null) {
128 // was already there? ignore
129 return false;
alshabiba68eb962014-09-24 20:34:13 -0700130 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700131 // new flow rule added
132 // TODO: notify through delegate about remote event?
133 return true;
alshabiba68eb962014-09-24 20:34:13 -0700134 }
135
136 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700137 public void deleteFlowRule(FlowRule rule) {
138
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -0700139 StoredFlowEntry entry = getFlowEntry(rule.deviceId(), rule.id());
alshabib1c319ff2014-10-04 20:29:09 -0700140 if (entry == null) {
Yuta HIGUCHI58e40432014-10-19 15:43:41 -0700141 //log.warn("Cannot find rule {}", rule);
alshabib1c319ff2014-10-04 20:29:09 -0700142 return;
alshabib219ebaa2014-09-22 15:41:24 -0700143 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700144 synchronized (entry) {
145 entry.setState(FlowEntryState.PENDING_REMOVE);
146 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700147 }
148
tombe988312014-09-19 18:38:47 -0700149 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700150 public FlowRuleEvent addOrUpdateFlowRule(FlowEntry rule) {
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700151 // check if this new rule is an update to an existing entry
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -0700152 StoredFlowEntry stored = getFlowEntry(rule.deviceId(), rule.id());
alshabibba5ac482014-10-02 17:15:20 -0700153 if (stored != null) {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700154 synchronized (stored) {
155 stored.setBytes(rule.bytes());
156 stored.setLife(rule.life());
157 stored.setPackets(rule.packets());
158 if (stored.state() == FlowEntryState.PENDING_ADD) {
159 stored.setState(FlowEntryState.ADDED);
160 // TODO: Do we need to change `rule` state?
161 return new FlowRuleEvent(Type.RULE_ADDED, rule);
162 }
163 return new FlowRuleEvent(Type.RULE_UPDATED, rule);
alshabibba5ac482014-10-02 17:15:20 -0700164 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700165 }
alshabib219ebaa2014-09-22 15:41:24 -0700166
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700167 // should not reach here
168 // storeFlowRule was expected to be called
169 log.error("FlowRule was not found in store {} to update", rule);
170
alshabib8ca53902014-10-07 13:11:17 -0700171 //flowEntries.put(did, rule);
alshabibba5ac482014-10-02 17:15:20 -0700172 return null;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700173 }
174
tombe988312014-09-19 18:38:47 -0700175 @Override
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700176 public FlowRuleEvent removeFlowRule(FlowEntry rule) {
alshabib1c319ff2014-10-04 20:29:09 -0700177 // This is where one could mark a rule as removed and still keep it in the store.
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700178 final DeviceId did = rule.deviceId();
179
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -0700180 ConcurrentMap<FlowId, StoredFlowEntry> ft = getFlowTable(did);
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700181 if (ft.remove(rule.id(), rule)) {
alshabiba68eb962014-09-24 20:34:13 -0700182 return new FlowRuleEvent(RULE_REMOVED, rule);
183 } else {
184 return null;
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700185 }
186 }
Ayaka Koshibe08eabaa2014-09-17 14:59:25 -0700187}