Committed by
Gerrit Code Review
Enhance StatisticService to allow filtering by Application ID and Group ID
Resolve ONOS-205 Change-Id: Ie9318a5ade943bd8e47fb92ee856b7ebead5022e
Showing
5 changed files
with
331 additions
and
7 deletions
| 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.core; | ||
| 17 | + | ||
| 18 | +import com.google.common.base.MoreObjects; | ||
| 19 | + | ||
| 20 | +import java.util.Objects; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * Default implementation of {@link GroupId}. | ||
| 24 | + */ | ||
| 25 | +public class DefaultGroupId implements GroupId { | ||
| 26 | + | ||
| 27 | + private final int id; | ||
| 28 | + | ||
| 29 | + public DefaultGroupId(int id) { | ||
| 30 | + this.id = id; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + // Constructor for serialization | ||
| 34 | + private DefaultGroupId() { | ||
| 35 | + this.id = 0; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + @Override | ||
| 39 | + public int id() { | ||
| 40 | + return 0; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public int hashCode() { | ||
| 45 | + return Objects.hash(id); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public boolean equals(Object obj) { | ||
| 50 | + if (this == obj) { | ||
| 51 | + return true; | ||
| 52 | + } | ||
| 53 | + if (!(obj instanceof DefaultGroupId)) { | ||
| 54 | + return false; | ||
| 55 | + } | ||
| 56 | + final DefaultGroupId other = (DefaultGroupId) obj; | ||
| 57 | + return Objects.equals(this.id, other.id); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @Override | ||
| 61 | + public String toString() { | ||
| 62 | + return MoreObjects.toStringHelper(this) | ||
| 63 | + .add("id", id) | ||
| 64 | + .toString(); | ||
| 65 | + } | ||
| 66 | +} |
| 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.core; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Group identifier. | ||
| 20 | + */ | ||
| 21 | +public interface GroupId { | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * Returns a group ID as short value. | ||
| 25 | + * The method is not intended for use by application developers. | ||
| 26 | + * Return data type may change in the future release. | ||
| 27 | + * | ||
| 28 | + * @return a group ID as short value | ||
| 29 | + */ | ||
| 30 | + int id(); | ||
| 31 | +} |
| ... | @@ -15,11 +15,15 @@ | ... | @@ -15,11 +15,15 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onlab.onos.net.statistic; | 16 | package org.onlab.onos.net.statistic; |
| 17 | 17 | ||
| 18 | +import org.onlab.onos.core.ApplicationId; | ||
| 19 | +import org.onlab.onos.core.GroupId; | ||
| 18 | import org.onlab.onos.net.ConnectPoint; | 20 | import org.onlab.onos.net.ConnectPoint; |
| 19 | import org.onlab.onos.net.Link; | 21 | import org.onlab.onos.net.Link; |
| 20 | import org.onlab.onos.net.Path; | 22 | import org.onlab.onos.net.Path; |
| 21 | import org.onlab.onos.net.flow.FlowRule; | 23 | import org.onlab.onos.net.flow.FlowRule; |
| 22 | 24 | ||
| 25 | +import java.util.Optional; | ||
| 26 | + | ||
| 23 | /** | 27 | /** |
| 24 | * Service for obtaining statistic information about link in the system. | 28 | * Service for obtaining statistic information about link in the system. |
| 25 | * Statistics are obtained from the FlowRuleService in order to minimize the | 29 | * Statistics are obtained from the FlowRuleService in order to minimize the |
| ... | @@ -68,4 +72,14 @@ public interface StatisticService { | ... | @@ -68,4 +72,14 @@ public interface StatisticService { |
| 68 | */ | 72 | */ |
| 69 | FlowRule highestHitter(ConnectPoint connectPoint); | 73 | FlowRule highestHitter(ConnectPoint connectPoint); |
| 70 | 74 | ||
| 75 | + /** | ||
| 76 | + * Obtain the load for a the ingress to the given link used by | ||
| 77 | + * the specified application ID and group ID. | ||
| 78 | + * | ||
| 79 | + * @param link link to query | ||
| 80 | + * @param appId application ID to filter with | ||
| 81 | + * @param groupId group ID to filter with | ||
| 82 | + * @return {@link Load Load} | ||
| 83 | + */ | ||
| 84 | + Load load(Link link, ApplicationId appId, Optional<GroupId> groupId); | ||
| 71 | } | 85 | } | ... | ... |
| 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.core; | ||
| 17 | + | ||
| 18 | +import com.google.common.testing.EqualsTester; | ||
| 19 | +import org.junit.Test; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * Test for DefaultGroupId. | ||
| 23 | + */ | ||
| 24 | +public class DefaultGroupIdTest { | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * Tests the equality of the instances. | ||
| 28 | + */ | ||
| 29 | + @Test | ||
| 30 | + public void testEquality() { | ||
| 31 | + DefaultGroupId id1 = new DefaultGroupId((short) 1); | ||
| 32 | + DefaultGroupId id2 = new DefaultGroupId((short) 1); | ||
| 33 | + DefaultGroupId id3 = new DefaultGroupId((short) 2); | ||
| 34 | + | ||
| 35 | + new EqualsTester() | ||
| 36 | + .addEqualityGroup(id1, id2) | ||
| 37 | + .addEqualityGroup(id3) | ||
| 38 | + .testEquals(); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | +} |
| ... | @@ -15,12 +15,18 @@ | ... | @@ -15,12 +15,18 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onlab.onos.net.statistic.impl; | 16 | package org.onlab.onos.net.statistic.impl; |
| 17 | 17 | ||
| 18 | +import com.google.common.base.MoreObjects; | ||
| 19 | +import com.google.common.base.Predicate; | ||
| 20 | +import com.google.common.collect.FluentIterable; | ||
| 21 | +import com.google.common.collect.ImmutableSet; | ||
| 18 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
| 19 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
| 20 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
| 21 | import org.apache.felix.scr.annotations.Reference; | 25 | import org.apache.felix.scr.annotations.Reference; |
| 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 26 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 23 | import org.apache.felix.scr.annotations.Service; | 27 | import org.apache.felix.scr.annotations.Service; |
| 28 | +import org.onlab.onos.core.ApplicationId; | ||
| 29 | +import org.onlab.onos.core.GroupId; | ||
| 24 | import org.onlab.onos.net.ConnectPoint; | 30 | import org.onlab.onos.net.ConnectPoint; |
| 25 | import org.onlab.onos.net.Link; | 31 | import org.onlab.onos.net.Link; |
| 26 | import org.onlab.onos.net.Path; | 32 | import org.onlab.onos.net.Path; |
| ... | @@ -35,8 +41,13 @@ import org.onlab.onos.net.statistic.Load; | ... | @@ -35,8 +41,13 @@ import org.onlab.onos.net.statistic.Load; |
| 35 | import org.onlab.onos.net.statistic.StatisticService; | 41 | import org.onlab.onos.net.statistic.StatisticService; |
| 36 | import org.onlab.onos.net.statistic.StatisticStore; | 42 | import org.onlab.onos.net.statistic.StatisticStore; |
| 37 | import org.slf4j.Logger; | 43 | import org.slf4j.Logger; |
| 44 | + | ||
| 45 | +import java.util.Collections; | ||
| 46 | +import java.util.Objects; | ||
| 47 | +import java.util.Optional; | ||
| 38 | import java.util.Set; | 48 | import java.util.Set; |
| 39 | 49 | ||
| 50 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 40 | import static org.slf4j.LoggerFactory.getLogger; | 51 | import static org.slf4j.LoggerFactory.getLogger; |
| 41 | 52 | ||
| 42 | /** | 53 | /** |
| ... | @@ -76,6 +87,25 @@ public class StatisticManager implements StatisticService { | ... | @@ -76,6 +87,25 @@ public class StatisticManager implements StatisticService { |
| 76 | } | 87 | } |
| 77 | 88 | ||
| 78 | @Override | 89 | @Override |
| 90 | + public Load load(Link link, ApplicationId appId, Optional<GroupId> groupId) { | ||
| 91 | + Statistics stats = getStatistics(link.src()); | ||
| 92 | + if (!stats.isValid()) { | ||
| 93 | + return new DefaultLoad(); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + ImmutableSet<FlowEntry> current = FluentIterable.from(stats.current()) | ||
| 97 | + .filter(hasApplicationId(appId)) | ||
| 98 | + .filter(hasGroupId(groupId)) | ||
| 99 | + .toSet(); | ||
| 100 | + ImmutableSet<FlowEntry> previous = FluentIterable.from(stats.previous()) | ||
| 101 | + .filter(hasApplicationId(appId)) | ||
| 102 | + .filter(hasGroupId(groupId)) | ||
| 103 | + .toSet(); | ||
| 104 | + | ||
| 105 | + return new DefaultLoad(aggregate(current), aggregate(previous)); | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + @Override | ||
| 79 | public Load load(ConnectPoint connectPoint) { | 109 | public Load load(ConnectPoint connectPoint) { |
| 80 | return loadInternal(connectPoint); | 110 | return loadInternal(connectPoint); |
| 81 | } | 111 | } |
| ... | @@ -131,21 +161,63 @@ public class StatisticManager implements StatisticService { | ... | @@ -131,21 +161,63 @@ public class StatisticManager implements StatisticService { |
| 131 | } | 161 | } |
| 132 | 162 | ||
| 133 | private Load loadInternal(ConnectPoint connectPoint) { | 163 | private Load loadInternal(ConnectPoint connectPoint) { |
| 164 | + Statistics stats = getStatistics(connectPoint); | ||
| 165 | + if (!stats.isValid()) { | ||
| 166 | + return new DefaultLoad(); | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + return new DefaultLoad(aggregate(stats.current), aggregate(stats.previous)); | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + /** | ||
| 173 | + * Returns statistics of the specified port. | ||
| 174 | + * | ||
| 175 | + * @param connectPoint port to query | ||
| 176 | + * @return statistics | ||
| 177 | + */ | ||
| 178 | + private Statistics getStatistics(ConnectPoint connectPoint) { | ||
| 134 | Set<FlowEntry> current; | 179 | Set<FlowEntry> current; |
| 135 | Set<FlowEntry> previous; | 180 | Set<FlowEntry> previous; |
| 136 | synchronized (statisticStore) { | 181 | synchronized (statisticStore) { |
| 137 | - current = statisticStore.getCurrentStatistic(connectPoint); | 182 | + current = getCurrentStatistic(connectPoint); |
| 138 | - previous = statisticStore.getPreviousStatistic(connectPoint); | 183 | + previous = getPreviousStatistic(connectPoint); |
| 139 | } | 184 | } |
| 140 | - if (current == null || previous == null) { | 185 | + |
| 141 | - return new DefaultLoad(); | 186 | + return new Statistics(current, previous); |
| 142 | } | 187 | } |
| 143 | - long currentAggregate = aggregate(current); | ||
| 144 | - long previousAggregate = aggregate(previous); | ||
| 145 | 188 | ||
| 146 | - return new DefaultLoad(currentAggregate, previousAggregate); | 189 | + /** |
| 190 | + * Returns the current statistic of the specified port. | ||
| 191 | + | ||
| 192 | + * @param connectPoint port to query | ||
| 193 | + * @return set of flow entries | ||
| 194 | + */ | ||
| 195 | + private Set<FlowEntry> getCurrentStatistic(ConnectPoint connectPoint) { | ||
| 196 | + Set<FlowEntry> stats = statisticStore.getCurrentStatistic(connectPoint); | ||
| 197 | + if (stats == null) { | ||
| 198 | + return Collections.emptySet(); | ||
| 199 | + } else { | ||
| 200 | + return stats; | ||
| 201 | + } | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + /** | ||
| 205 | + * Returns the previous statistic of the specified port. | ||
| 206 | + * | ||
| 207 | + * @param connectPoint port to query | ||
| 208 | + * @return set of flow entries | ||
| 209 | + */ | ||
| 210 | + private Set<FlowEntry> getPreviousStatistic(ConnectPoint connectPoint) { | ||
| 211 | + Set<FlowEntry> stats = statisticStore.getCurrentStatistic(connectPoint); | ||
| 212 | + if (stats == null) { | ||
| 213 | + return Collections.emptySet(); | ||
| 214 | + } else { | ||
| 215 | + return stats; | ||
| 216 | + } | ||
| 147 | } | 217 | } |
| 148 | 218 | ||
| 219 | + // TODO: make aggregation function generic by passing a function | ||
| 220 | + // (applying Java 8 Stream API?) | ||
| 149 | /** | 221 | /** |
| 150 | * Aggregates a set of values. | 222 | * Aggregates a set of values. |
| 151 | * @param values the values to aggregate | 223 | * @param values the values to aggregate |
| ... | @@ -188,5 +260,105 @@ public class StatisticManager implements StatisticService { | ... | @@ -188,5 +260,105 @@ public class StatisticManager implements StatisticService { |
| 188 | } | 260 | } |
| 189 | } | 261 | } |
| 190 | 262 | ||
| 263 | + /** | ||
| 264 | + * Internal data class holding two set of flow entries. | ||
| 265 | + */ | ||
| 266 | + private static class Statistics { | ||
| 267 | + private final ImmutableSet<FlowEntry> current; | ||
| 268 | + private final ImmutableSet<FlowEntry> previous; | ||
| 269 | + | ||
| 270 | + public Statistics(Set<FlowEntry> current, Set<FlowEntry> previous) { | ||
| 271 | + this.current = ImmutableSet.copyOf(checkNotNull(current)); | ||
| 272 | + this.previous = ImmutableSet.copyOf(checkNotNull(previous)); | ||
| 273 | + } | ||
| 274 | + | ||
| 275 | + /** | ||
| 276 | + * Returns flow entries as the current value. | ||
| 277 | + * | ||
| 278 | + * @return flow entries as the current value | ||
| 279 | + */ | ||
| 280 | + public ImmutableSet<FlowEntry> current() { | ||
| 281 | + return current; | ||
| 282 | + } | ||
| 191 | 283 | ||
| 284 | + /** | ||
| 285 | + * Returns flow entries as the previous value. | ||
| 286 | + * | ||
| 287 | + * @return flow entries as the previous value | ||
| 288 | + */ | ||
| 289 | + public ImmutableSet<FlowEntry> previous() { | ||
| 290 | + return previous; | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + /** | ||
| 294 | + * Validates values are not empty. | ||
| 295 | + * | ||
| 296 | + * @return false if either of the sets is empty. Otherwise, true. | ||
| 297 | + */ | ||
| 298 | + public boolean isValid() { | ||
| 299 | + return !(current.isEmpty() || previous.isEmpty()); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + @Override | ||
| 303 | + public int hashCode() { | ||
| 304 | + return Objects.hash(current, previous); | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + @Override | ||
| 308 | + public boolean equals(Object obj) { | ||
| 309 | + if (this == obj) { | ||
| 310 | + return true; | ||
| 311 | + } | ||
| 312 | + if (!(obj instanceof Statistics)) { | ||
| 313 | + return false; | ||
| 314 | + } | ||
| 315 | + final Statistics other = (Statistics) obj; | ||
| 316 | + return Objects.equals(this.current, other.current) && Objects.equals(this.previous, other.previous); | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + @Override | ||
| 320 | + public String toString() { | ||
| 321 | + return MoreObjects.toStringHelper(this) | ||
| 322 | + .add("current", current) | ||
| 323 | + .add("previous", previous) | ||
| 324 | + .toString(); | ||
| 325 | + } | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + /** | ||
| 329 | + * Creates a predicate that checks the application ID of a flow entry is the same as | ||
| 330 | + * the specified application ID. | ||
| 331 | + * | ||
| 332 | + * @param appId application ID to be checked | ||
| 333 | + * @return predicate | ||
| 334 | + */ | ||
| 335 | + private static Predicate<FlowEntry> hasApplicationId(ApplicationId appId) { | ||
| 336 | + return new Predicate<FlowEntry>() { | ||
| 337 | + @Override | ||
| 338 | + public boolean apply(FlowEntry flowEntry) { | ||
| 339 | + return flowEntry.appId() == appId.id(); | ||
| 340 | + } | ||
| 341 | + }; | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + /** | ||
| 345 | + * Create a predicate that checks the group ID of a flow entry is the same as | ||
| 346 | + * the specified group ID. | ||
| 347 | + * | ||
| 348 | + * @param groupId group ID to be checked | ||
| 349 | + * @return predicate | ||
| 350 | + */ | ||
| 351 | + private static Predicate<FlowEntry> hasGroupId(Optional<GroupId> groupId) { | ||
| 352 | + return new Predicate<FlowEntry>() { | ||
| 353 | + @Override | ||
| 354 | + public boolean apply(FlowEntry flowEntry) { | ||
| 355 | + if (!groupId.isPresent()) { | ||
| 356 | + return false; | ||
| 357 | + } | ||
| 358 | + // FIXME: The left hand type and right hand type don't match | ||
| 359 | + // FlowEntry.groupId() still returns a short value, not int. | ||
| 360 | + return flowEntry.groupId() == groupId.get().id(); | ||
| 361 | + } | ||
| 362 | + }; | ||
| 363 | + } | ||
| 192 | } | 364 | } | ... | ... |
-
Please register or login to post a comment