blob: 9cfa41d7f7d3a285b4a769f113fe4effa2d3a1f6 [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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.trivial.impl;
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080017
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080023import org.onosproject.net.ConnectPoint;
24import org.onosproject.net.PortNumber;
25import org.onosproject.net.flow.FlowEntry;
26import org.onosproject.net.flow.FlowRule;
27import org.onosproject.net.flow.instructions.Instruction;
28import org.onosproject.net.flow.instructions.Instructions;
29import org.onosproject.net.statistic.StatisticStore;
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080030import 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);
Jonathan Hart7baba072015-02-23 14:27:59 -0800157
158 boolean hasGoto = rule.treatment().instructions()
159 .stream()
160 .anyMatch(i -> (i instanceof Instructions.GroupInstruction)
161 || (i instanceof Instructions.TableTypeTransition));
162
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800163 if (port == null) {
Jonathan Hart7baba072015-02-23 14:27:59 -0800164 if (!hasGoto) {
165 log.debug("Rule {} has no output.", rule);
166 }
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800167 return null;
168 }
169 ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
170 return cp;
171 }
172
173 private PortNumber getOutput(FlowRule rule) {
174 for (Instruction i : rule.treatment().instructions()) {
175 if (i.type() == Instruction.Type.OUTPUT) {
176 Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
177 return out.port();
178 }
179 if (i.type() == Instruction.Type.DROP) {
180 return PortNumber.P0;
181 }
182 }
183 return null;
184 }
185
186 private class InternalStatisticRepresentation {
187
188 private final AtomicInteger counter = new AtomicInteger(0);
189 private final Set<FlowEntry> rules = new HashSet<>();
190
191 public void prepare() {
192 counter.incrementAndGet();
193 }
194
alshabib9c57bdd2014-11-28 19:14:06 -0500195 public synchronized boolean remove(FlowRule rule) {
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800196 rules.remove(rule);
alshabib9c57bdd2014-11-28 19:14:06 -0500197 return counter.decrementAndGet() == 0;
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800198 }
199
200 public synchronized boolean submit(FlowEntry rule) {
201 if (rules.contains(rule)) {
202 rules.remove(rule);
203 }
204 rules.add(rule);
205 if (counter.get() == 0) {
206 return true;
207 } else {
208 return counter.decrementAndGet() == 0;
209 }
210 }
211
212 public synchronized Set<FlowEntry> get() {
213 counter.set(rules.size());
214 return Sets.newHashSet(rules);
215 }
216
217 }
218
219}