blob: d8bb32fdac1645c03a580f10b2c7dee212dd733c [file] [log] [blame]
Thomas Vachuska7c27ad72014-11-14 16:20:10 -08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onlab.onos.store.trivial.impl;
17
18import com.google.common.collect.Sets;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Service;
23import org.onlab.onos.net.ConnectPoint;
24import org.onlab.onos.net.PortNumber;
25import org.onlab.onos.net.flow.FlowEntry;
26import org.onlab.onos.net.flow.FlowRule;
27import org.onlab.onos.net.flow.instructions.Instruction;
28import org.onlab.onos.net.flow.instructions.Instructions;
29import org.onlab.onos.net.statistic.StatisticStore;
30import org.slf4j.Logger;
31
alshabib9c57bdd2014-11-28 19:14:06 -050032import java.util.Collections;
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080033import java.util.HashSet;
34import java.util.Map;
35import java.util.Set;
36import java.util.concurrent.ConcurrentHashMap;
37import java.util.concurrent.atomic.AtomicInteger;
38
39import static org.slf4j.LoggerFactory.getLogger;
40
41
42/**
43 * Maintains statistics using RPC calls to collect stats from remote instances
44 * on demand.
45 */
46@Component(immediate = true)
47@Service
48public class SimpleStatisticStore implements StatisticStore {
49
50 private final Logger log = getLogger(getClass());
51
52 private Map<ConnectPoint, InternalStatisticRepresentation>
53 representations = new ConcurrentHashMap<>();
54
55 private Map<ConnectPoint, Set<FlowEntry>> previous = new ConcurrentHashMap<>();
56 private Map<ConnectPoint, Set<FlowEntry>> current = new ConcurrentHashMap<>();
57
58 @Activate
59 public void activate() {
60 log.info("Started");
61 }
62
63 @Deactivate
64 public void deactivate() {
65 log.info("Stopped");
66 }
67
68 @Override
69 public void prepareForStatistics(FlowRule rule) {
70 ConnectPoint cp = buildConnectPoint(rule);
71 if (cp == null) {
72 return;
73 }
74 InternalStatisticRepresentation rep;
75 synchronized (representations) {
76 rep = getOrCreateRepresentation(cp);
77 }
78 rep.prepare();
79 }
80
81 @Override
82 public synchronized void removeFromStatistics(FlowRule rule) {
83 ConnectPoint cp = buildConnectPoint(rule);
84 if (cp == null) {
85 return;
86 }
87 InternalStatisticRepresentation rep = representations.get(cp);
alshabib9c57bdd2014-11-28 19:14:06 -050088 if (rep != null && rep.remove(rule)) {
89 updatePublishedStats(cp, Collections.emptySet());
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080090 }
91 Set<FlowEntry> values = current.get(cp);
92 if (values != null) {
93 values.remove(rule);
94 }
95 values = previous.get(cp);
96 if (values != null) {
97 values.remove(rule);
98 }
99
100 }
101
102 @Override
103 public void addOrUpdateStatistic(FlowEntry rule) {
104 ConnectPoint cp = buildConnectPoint(rule);
105 if (cp == null) {
106 return;
107 }
108 InternalStatisticRepresentation rep = representations.get(cp);
109 if (rep != null && rep.submit(rule)) {
110 updatePublishedStats(cp, rep.get());
111 }
112 }
113
114 private synchronized void updatePublishedStats(ConnectPoint cp,
115 Set<FlowEntry> flowEntries) {
116 Set<FlowEntry> curr = current.get(cp);
117 if (curr == null) {
118 curr = new HashSet<>();
119 }
120 previous.put(cp, curr);
121 current.put(cp, flowEntries);
122
123 }
124
125 @Override
126 public Set<FlowEntry> getCurrentStatistic(ConnectPoint connectPoint) {
127 return getCurrentStatisticInternal(connectPoint);
128 }
129
130 private synchronized Set<FlowEntry> getCurrentStatisticInternal(ConnectPoint connectPoint) {
131 return current.get(connectPoint);
132 }
133
134 @Override
135 public Set<FlowEntry> getPreviousStatistic(ConnectPoint connectPoint) {
136 return getPreviousStatisticInternal(connectPoint);
137 }
138
139 private synchronized Set<FlowEntry> getPreviousStatisticInternal(ConnectPoint connectPoint) {
140 return previous.get(connectPoint);
141 }
142
143 private InternalStatisticRepresentation getOrCreateRepresentation(ConnectPoint cp) {
144
145 if (representations.containsKey(cp)) {
146 return representations.get(cp);
147 } else {
148 InternalStatisticRepresentation rep = new InternalStatisticRepresentation();
149 representations.put(cp, rep);
150 return rep;
151 }
152
153 }
154
155 private ConnectPoint buildConnectPoint(FlowRule rule) {
156 PortNumber port = getOutput(rule);
157 if (port == null) {
Brian O'Connorfaaedf42014-11-17 14:48:48 -0800158 log.debug("Rule {} has no output.", rule);
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800159 return null;
160 }
161 ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
162 return cp;
163 }
164
165 private PortNumber getOutput(FlowRule rule) {
166 for (Instruction i : rule.treatment().instructions()) {
167 if (i.type() == Instruction.Type.OUTPUT) {
168 Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
169 return out.port();
170 }
171 if (i.type() == Instruction.Type.DROP) {
172 return PortNumber.P0;
173 }
174 }
175 return null;
176 }
177
178 private class InternalStatisticRepresentation {
179
180 private final AtomicInteger counter = new AtomicInteger(0);
181 private final Set<FlowEntry> rules = new HashSet<>();
182
183 public void prepare() {
184 counter.incrementAndGet();
185 }
186
alshabib9c57bdd2014-11-28 19:14:06 -0500187 public synchronized boolean remove(FlowRule rule) {
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800188 rules.remove(rule);
alshabib9c57bdd2014-11-28 19:14:06 -0500189 return counter.decrementAndGet() == 0;
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800190 }
191
192 public synchronized boolean submit(FlowEntry rule) {
193 if (rules.contains(rule)) {
194 rules.remove(rule);
195 }
196 rules.add(rule);
197 if (counter.get() == 0) {
198 return true;
199 } else {
200 return counter.decrementAndGet() == 0;
201 }
202 }
203
204 public synchronized Set<FlowEntry> get() {
205 counter.set(rules.size());
206 return Sets.newHashSet(rules);
207 }
208
209 }
210
211}