Added detection of traffic flowing using StatisticService.
Change-Id: I2044ec16fd722d953d0e2b2c955e4da2b1dab663
Showing
5 changed files
with
232 additions
and
19 deletions
| ... | @@ -25,7 +25,7 @@ import java.util.concurrent.Future; | ... | @@ -25,7 +25,7 @@ import java.util.concurrent.Future; |
| 25 | */ | 25 | */ |
| 26 | public interface FlowRuleProvider extends Provider { | 26 | public interface FlowRuleProvider extends Provider { |
| 27 | 27 | ||
| 28 | - static final int POLL_INTERVAL = 5; | 28 | + static final int POLL_INTERVAL = 1; |
| 29 | 29 | ||
| 30 | /** | 30 | /** |
| 31 | * Instructs the provider to apply the specified flow rules to their | 31 | * Instructs the provider to apply the specified flow rules to their | ... | ... |
core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleStatisticStore.java
0 → 100644
| 1 | +/* | ||
| 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 | + */ | ||
| 16 | +package org.onlab.onos.store.trivial.impl; | ||
| 17 | + | ||
| 18 | +import com.google.common.collect.Sets; | ||
| 19 | +import org.apache.felix.scr.annotations.Activate; | ||
| 20 | +import org.apache.felix.scr.annotations.Component; | ||
| 21 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 22 | +import org.apache.felix.scr.annotations.Service; | ||
| 23 | +import org.onlab.onos.net.ConnectPoint; | ||
| 24 | +import org.onlab.onos.net.PortNumber; | ||
| 25 | +import org.onlab.onos.net.flow.FlowEntry; | ||
| 26 | +import org.onlab.onos.net.flow.FlowRule; | ||
| 27 | +import org.onlab.onos.net.flow.instructions.Instruction; | ||
| 28 | +import org.onlab.onos.net.flow.instructions.Instructions; | ||
| 29 | +import org.onlab.onos.net.statistic.StatisticStore; | ||
| 30 | +import org.slf4j.Logger; | ||
| 31 | + | ||
| 32 | +import java.util.HashSet; | ||
| 33 | +import java.util.Map; | ||
| 34 | +import java.util.Set; | ||
| 35 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 36 | +import java.util.concurrent.atomic.AtomicInteger; | ||
| 37 | + | ||
| 38 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +/** | ||
| 42 | + * Maintains statistics using RPC calls to collect stats from remote instances | ||
| 43 | + * on demand. | ||
| 44 | + */ | ||
| 45 | +@Component(immediate = true) | ||
| 46 | +@Service | ||
| 47 | +public class SimpleStatisticStore implements StatisticStore { | ||
| 48 | + | ||
| 49 | + private final Logger log = getLogger(getClass()); | ||
| 50 | + | ||
| 51 | + private Map<ConnectPoint, InternalStatisticRepresentation> | ||
| 52 | + representations = new ConcurrentHashMap<>(); | ||
| 53 | + | ||
| 54 | + private Map<ConnectPoint, Set<FlowEntry>> previous = new ConcurrentHashMap<>(); | ||
| 55 | + private Map<ConnectPoint, Set<FlowEntry>> current = new ConcurrentHashMap<>(); | ||
| 56 | + | ||
| 57 | + @Activate | ||
| 58 | + public void activate() { | ||
| 59 | + log.info("Started"); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Deactivate | ||
| 63 | + public void deactivate() { | ||
| 64 | + log.info("Stopped"); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @Override | ||
| 68 | + public void prepareForStatistics(FlowRule rule) { | ||
| 69 | + ConnectPoint cp = buildConnectPoint(rule); | ||
| 70 | + if (cp == null) { | ||
| 71 | + return; | ||
| 72 | + } | ||
| 73 | + InternalStatisticRepresentation rep; | ||
| 74 | + synchronized (representations) { | ||
| 75 | + rep = getOrCreateRepresentation(cp); | ||
| 76 | + } | ||
| 77 | + rep.prepare(); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public synchronized void removeFromStatistics(FlowRule rule) { | ||
| 82 | + ConnectPoint cp = buildConnectPoint(rule); | ||
| 83 | + if (cp == null) { | ||
| 84 | + return; | ||
| 85 | + } | ||
| 86 | + InternalStatisticRepresentation rep = representations.get(cp); | ||
| 87 | + if (rep != null) { | ||
| 88 | + rep.remove(rule); | ||
| 89 | + } | ||
| 90 | + Set<FlowEntry> values = current.get(cp); | ||
| 91 | + if (values != null) { | ||
| 92 | + values.remove(rule); | ||
| 93 | + } | ||
| 94 | + values = previous.get(cp); | ||
| 95 | + if (values != null) { | ||
| 96 | + values.remove(rule); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + @Override | ||
| 102 | + public void addOrUpdateStatistic(FlowEntry rule) { | ||
| 103 | + ConnectPoint cp = buildConnectPoint(rule); | ||
| 104 | + if (cp == null) { | ||
| 105 | + return; | ||
| 106 | + } | ||
| 107 | + InternalStatisticRepresentation rep = representations.get(cp); | ||
| 108 | + if (rep != null && rep.submit(rule)) { | ||
| 109 | + updatePublishedStats(cp, rep.get()); | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + private synchronized void updatePublishedStats(ConnectPoint cp, | ||
| 114 | + Set<FlowEntry> flowEntries) { | ||
| 115 | + Set<FlowEntry> curr = current.get(cp); | ||
| 116 | + if (curr == null) { | ||
| 117 | + curr = new HashSet<>(); | ||
| 118 | + } | ||
| 119 | + previous.put(cp, curr); | ||
| 120 | + current.put(cp, flowEntries); | ||
| 121 | + | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + @Override | ||
| 125 | + public Set<FlowEntry> getCurrentStatistic(ConnectPoint connectPoint) { | ||
| 126 | + return getCurrentStatisticInternal(connectPoint); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + private synchronized Set<FlowEntry> getCurrentStatisticInternal(ConnectPoint connectPoint) { | ||
| 130 | + return current.get(connectPoint); | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + @Override | ||
| 134 | + public Set<FlowEntry> getPreviousStatistic(ConnectPoint connectPoint) { | ||
| 135 | + return getPreviousStatisticInternal(connectPoint); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + private synchronized Set<FlowEntry> getPreviousStatisticInternal(ConnectPoint connectPoint) { | ||
| 139 | + return previous.get(connectPoint); | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + private InternalStatisticRepresentation getOrCreateRepresentation(ConnectPoint cp) { | ||
| 143 | + | ||
| 144 | + if (representations.containsKey(cp)) { | ||
| 145 | + return representations.get(cp); | ||
| 146 | + } else { | ||
| 147 | + InternalStatisticRepresentation rep = new InternalStatisticRepresentation(); | ||
| 148 | + representations.put(cp, rep); | ||
| 149 | + return rep; | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + private ConnectPoint buildConnectPoint(FlowRule rule) { | ||
| 155 | + PortNumber port = getOutput(rule); | ||
| 156 | + if (port == null) { | ||
| 157 | + log.warn("Rule {} has no output.", rule); | ||
| 158 | + return null; | ||
| 159 | + } | ||
| 160 | + ConnectPoint cp = new ConnectPoint(rule.deviceId(), port); | ||
| 161 | + return cp; | ||
| 162 | + } | ||
| 163 | + | ||
| 164 | + private PortNumber getOutput(FlowRule rule) { | ||
| 165 | + for (Instruction i : rule.treatment().instructions()) { | ||
| 166 | + if (i.type() == Instruction.Type.OUTPUT) { | ||
| 167 | + Instructions.OutputInstruction out = (Instructions.OutputInstruction) i; | ||
| 168 | + return out.port(); | ||
| 169 | + } | ||
| 170 | + if (i.type() == Instruction.Type.DROP) { | ||
| 171 | + return PortNumber.P0; | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + return null; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + private class InternalStatisticRepresentation { | ||
| 178 | + | ||
| 179 | + private final AtomicInteger counter = new AtomicInteger(0); | ||
| 180 | + private final Set<FlowEntry> rules = new HashSet<>(); | ||
| 181 | + | ||
| 182 | + public void prepare() { | ||
| 183 | + counter.incrementAndGet(); | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + public synchronized void remove(FlowRule rule) { | ||
| 187 | + rules.remove(rule); | ||
| 188 | + counter.decrementAndGet(); | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | + public synchronized boolean submit(FlowEntry rule) { | ||
| 192 | + if (rules.contains(rule)) { | ||
| 193 | + rules.remove(rule); | ||
| 194 | + } | ||
| 195 | + rules.add(rule); | ||
| 196 | + if (counter.get() == 0) { | ||
| 197 | + return true; | ||
| 198 | + } else { | ||
| 199 | + return counter.decrementAndGet() == 0; | ||
| 200 | + } | ||
| 201 | + } | ||
| 202 | + | ||
| 203 | + public synchronized Set<FlowEntry> get() { | ||
| 204 | + counter.set(rules.size()); | ||
| 205 | + return Sets.newHashSet(rules); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + } | ||
| 209 | + | ||
| 210 | +} |
| ... | @@ -37,7 +37,7 @@ public class GuiWebSocketServlet extends WebSocketServlet { | ... | @@ -37,7 +37,7 @@ public class GuiWebSocketServlet extends WebSocketServlet { |
| 37 | 37 | ||
| 38 | private ServiceDirectory directory = new DefaultServiceDirectory(); | 38 | private ServiceDirectory directory = new DefaultServiceDirectory(); |
| 39 | 39 | ||
| 40 | - private final Set<TopologyWebSocket> sockets = new HashSet<>(); | 40 | + private final Set<TopologyViewWebSocket> sockets = new HashSet<>(); |
| 41 | private final Timer timer = new Timer(); | 41 | private final Timer timer = new Timer(); |
| 42 | private final TimerTask pruner = new Pruner(); | 42 | private final TimerTask pruner = new Pruner(); |
| 43 | 43 | ||
| ... | @@ -49,7 +49,7 @@ public class GuiWebSocketServlet extends WebSocketServlet { | ... | @@ -49,7 +49,7 @@ public class GuiWebSocketServlet extends WebSocketServlet { |
| 49 | 49 | ||
| 50 | @Override | 50 | @Override |
| 51 | public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) { | 51 | public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) { |
| 52 | - TopologyWebSocket socket = new TopologyWebSocket(directory); | 52 | + TopologyViewWebSocket socket = new TopologyViewWebSocket(directory); |
| 53 | synchronized (sockets) { | 53 | synchronized (sockets) { |
| 54 | sockets.add(socket); | 54 | sockets.add(socket); |
| 55 | } | 55 | } |
| ... | @@ -61,9 +61,9 @@ public class GuiWebSocketServlet extends WebSocketServlet { | ... | @@ -61,9 +61,9 @@ public class GuiWebSocketServlet extends WebSocketServlet { |
| 61 | @Override | 61 | @Override |
| 62 | public void run() { | 62 | public void run() { |
| 63 | synchronized (sockets) { | 63 | synchronized (sockets) { |
| 64 | - Iterator<TopologyWebSocket> it = sockets.iterator(); | 64 | + Iterator<TopologyViewWebSocket> it = sockets.iterator(); |
| 65 | while (it.hasNext()) { | 65 | while (it.hasNext()) { |
| 66 | - TopologyWebSocket socket = it.next(); | 66 | + TopologyViewWebSocket socket = it.next(); |
| 67 | if (socket.isIdle()) { | 67 | if (socket.isIdle()) { |
| 68 | it.remove(); | 68 | it.remove(); |
| 69 | socket.close(); | 69 | socket.close(); | ... | ... |
| ... | @@ -49,6 +49,8 @@ import org.onlab.onos.net.intent.PathIntent; | ... | @@ -49,6 +49,8 @@ import org.onlab.onos.net.intent.PathIntent; |
| 49 | import org.onlab.onos.net.link.LinkEvent; | 49 | import org.onlab.onos.net.link.LinkEvent; |
| 50 | import org.onlab.onos.net.link.LinkService; | 50 | import org.onlab.onos.net.link.LinkService; |
| 51 | import org.onlab.onos.net.provider.ProviderId; | 51 | import org.onlab.onos.net.provider.ProviderId; |
| 52 | +import org.onlab.onos.net.statistic.Load; | ||
| 53 | +import org.onlab.onos.net.statistic.StatisticService; | ||
| 52 | import org.onlab.osgi.ServiceDirectory; | 54 | import org.onlab.osgi.ServiceDirectory; |
| 53 | import org.onlab.packet.IpAddress; | 55 | import org.onlab.packet.IpAddress; |
| 54 | import org.slf4j.Logger; | 56 | import org.slf4j.Logger; |
| ... | @@ -75,9 +77,9 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED; | ... | @@ -75,9 +77,9 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED; |
| 75 | /** | 77 | /** |
| 76 | * Facility for creating messages bound for the topology viewer. | 78 | * Facility for creating messages bound for the topology viewer. |
| 77 | */ | 79 | */ |
| 78 | -public abstract class TopologyMessages { | 80 | +public abstract class TopologyViewMessages { |
| 79 | 81 | ||
| 80 | - protected static final Logger log = LoggerFactory.getLogger(TopologyMessages.class); | 82 | + protected static final Logger log = LoggerFactory.getLogger(TopologyViewMessages.class); |
| 81 | 83 | ||
| 82 | private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true); | 84 | private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true); |
| 83 | private static final String COMPACT = "%s/%s-%s/%s"; | 85 | private static final String COMPACT = "%s/%s-%s/%s"; |
| ... | @@ -89,7 +91,7 @@ public abstract class TopologyMessages { | ... | @@ -89,7 +91,7 @@ public abstract class TopologyMessages { |
| 89 | protected final HostService hostService; | 91 | protected final HostService hostService; |
| 90 | protected final MastershipService mastershipService; | 92 | protected final MastershipService mastershipService; |
| 91 | protected final IntentService intentService; | 93 | protected final IntentService intentService; |
| 92 | -// protected final StatisticService statService; | 94 | + protected final StatisticService statService; |
| 93 | 95 | ||
| 94 | protected final ObjectMapper mapper = new ObjectMapper(); | 96 | protected final ObjectMapper mapper = new ObjectMapper(); |
| 95 | 97 | ||
| ... | @@ -101,7 +103,7 @@ public abstract class TopologyMessages { | ... | @@ -101,7 +103,7 @@ public abstract class TopologyMessages { |
| 101 | * | 103 | * |
| 102 | * @param directory service directory | 104 | * @param directory service directory |
| 103 | */ | 105 | */ |
| 104 | - protected TopologyMessages(ServiceDirectory directory) { | 106 | + protected TopologyViewMessages(ServiceDirectory directory) { |
| 105 | this.directory = checkNotNull(directory, "Directory cannot be null"); | 107 | this.directory = checkNotNull(directory, "Directory cannot be null"); |
| 106 | clusterService = directory.get(ClusterService.class); | 108 | clusterService = directory.get(ClusterService.class); |
| 107 | deviceService = directory.get(DeviceService.class); | 109 | deviceService = directory.get(DeviceService.class); |
| ... | @@ -109,7 +111,7 @@ public abstract class TopologyMessages { | ... | @@ -109,7 +111,7 @@ public abstract class TopologyMessages { |
| 109 | hostService = directory.get(HostService.class); | 111 | hostService = directory.get(HostService.class); |
| 110 | mastershipService = directory.get(MastershipService.class); | 112 | mastershipService = directory.get(MastershipService.class); |
| 111 | intentService = directory.get(IntentService.class); | 113 | intentService = directory.get(IntentService.class); |
| 112 | -// statService = directory.get(StatisticService.class); | 114 | + statService = directory.get(StatisticService.class); |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 115 | // Retrieves the payload from the specified event. | 117 | // Retrieves the payload from the specified event. |
| ... | @@ -408,14 +410,15 @@ public abstract class TopologyMessages { | ... | @@ -408,14 +410,15 @@ public abstract class TopologyMessages { |
| 408 | 410 | ||
| 409 | if (links != null) { | 411 | if (links != null) { |
| 410 | ArrayNode labels = mapper.createArrayNode(); | 412 | ArrayNode labels = mapper.createArrayNode(); |
| 411 | - boolean hasTraffic = true; // FIXME | 413 | + boolean hasTraffic = false; |
| 412 | for (Link link : links) { | 414 | for (Link link : links) { |
| 413 | linksNode.add(compactLinkString(link)); | 415 | linksNode.add(compactLinkString(link)); |
| 414 | -// Load load = statService.load(link); | 416 | + Load load = statService.load(link); |
| 415 | String label = ""; | 417 | String label = ""; |
| 416 | -// if (load.rate() > 0) { | 418 | + if (load.rate() > 0) { |
| 417 | -// label = load.toString(); | 419 | + hasTraffic = true; |
| 418 | -// } | 420 | + label = load.toString(); |
| 421 | + } | ||
| 419 | labels.add(label); | 422 | labels.add(label); |
| 420 | } | 423 | } |
| 421 | pathNode.put("class", hasTraffic ? type + " animated" : type); | 424 | pathNode.put("class", hasTraffic ? type + " animated" : type); | ... | ... |
| ... | @@ -66,8 +66,8 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED; | ... | @@ -66,8 +66,8 @@ import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED; |
| 66 | /** | 66 | /** |
| 67 | * Web socket capable of interacting with the GUI topology view. | 67 | * Web socket capable of interacting with the GUI topology view. |
| 68 | */ | 68 | */ |
| 69 | -public class TopologyWebSocket | 69 | +public class TopologyViewWebSocket |
| 70 | - extends TopologyMessages | 70 | + extends TopologyViewMessages |
| 71 | implements WebSocket.OnTextMessage, WebSocket.OnControl { | 71 | implements WebSocket.OnTextMessage, WebSocket.OnControl { |
| 72 | 72 | ||
| 73 | private static final long MAX_AGE_MS = 15000; | 73 | private static final long MAX_AGE_MS = 15000; |
| ... | @@ -78,7 +78,7 @@ public class TopologyWebSocket | ... | @@ -78,7 +78,7 @@ public class TopologyWebSocket |
| 78 | 78 | ||
| 79 | private static final String APP_ID = "org.onlab.onos.gui"; | 79 | private static final String APP_ID = "org.onlab.onos.gui"; |
| 80 | 80 | ||
| 81 | - private static final long TRAFFIC_FREQUENCY_SEC = 5000; | 81 | + private static final long TRAFFIC_FREQUENCY_SEC = 1000; |
| 82 | 82 | ||
| 83 | private final ApplicationId appId; | 83 | private final ApplicationId appId; |
| 84 | 84 | ||
| ... | @@ -104,7 +104,7 @@ public class TopologyWebSocket | ... | @@ -104,7 +104,7 @@ public class TopologyWebSocket |
| 104 | * | 104 | * |
| 105 | * @param directory service directory | 105 | * @param directory service directory |
| 106 | */ | 106 | */ |
| 107 | - public TopologyWebSocket(ServiceDirectory directory) { | 107 | + public TopologyViewWebSocket(ServiceDirectory directory) { |
| 108 | super(directory); | 108 | super(directory); |
| 109 | appId = directory.get(CoreService.class).registerApplication(APP_ID); | 109 | appId = directory.get(CoreService.class).registerApplication(APP_ID); |
| 110 | } | 110 | } | ... | ... |
-
Please register or login to post a comment