From fd86fa6e41609f160cd26ef8af3d2cf02adfe7d4 Mon Sep 17 00:00:00 2001 From: Jordan Halterman Date: Mon, 4 Mar 2019 18:12:20 -0800 Subject: [PATCH] Optimize filtering flow rule counts by state Change-Id: I1e1d80b8e618743ee449162a081cf42e71c99abf --- .../onosproject/cli/net/FlowsListCommand.java | 11 +++- .../onosproject/net/flow/FlowRuleService.java | 13 ++++ .../onosproject/net/flow/FlowRuleStore.java | 13 ++++ .../net/flow/impl/FlowRuleManager.java | 7 +++ .../store/flow/impl/ECFlowRuleStore.java | 60 +++++++++++++++---- .../rest/resources/StatisticsWebResource.java | 3 +- 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java b/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java index 5c26b06304..734bfec3c4 100644 --- a/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java +++ b/cli/src/main/java/org/onosproject/cli/net/FlowsListCommand.java @@ -120,12 +120,15 @@ public class FlowsListCommand extends AbstractShellCommand { compilePredicate(); if (countOnly && !suppressCoreOutput && filter.isEmpty() && remove == null) { - if (uri == null) { + if (state == null && uri == null) { deviceService.getDevices().forEach(device -> printCount(device, service)); + } else if (uri == null) { + deviceService.getDevices() + .forEach(device -> printCount(device, FlowEntryState.valueOf(state.toUpperCase()), service)); } else { Device device = deviceService.getDevice(DeviceId.deviceId(uri)); if (device != null) { - printCount(device, service); + printCount(device, FlowEntryState.valueOf(state.toUpperCase()), service); } } return; @@ -294,6 +297,10 @@ public class FlowsListCommand extends AbstractShellCommand { print("deviceId=%s, flowRuleCount=%d", device.id(), flowRuleService.getFlowRuleCount(device.id())); } + private void printCount(Device device, FlowEntryState state, FlowRuleService flowRuleService) { + print("deviceId=%s, flowRuleCount=%d", device.id(), flowRuleService.getFlowRuleCount(device.id(), state)); + } + /** * Prints flows. * diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java index 0ade2ed141..c682558e9d 100644 --- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java +++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java @@ -52,6 +52,17 @@ public interface FlowRuleService return 0; } + /** + * Returns the number of flow rules in the given state for the given device. + * + * @param deviceId the device identifier + * @param state the state for which to count flow rules + * @return number of flow rules in the given state for the given device + */ + default int getFlowRuleCount(DeviceId deviceId, FlowEntry.FlowEntryState state) { + return 0; + } + /** * Returns the collection of flow entries applied on the specified device. * This will include flow rules which may not yet have been applied to @@ -171,7 +182,9 @@ public interface FlowRuleService * * @param deviceId device identifier * @return number of flow rules in ADDED state + * @deprecated since 2.1 */ + @Deprecated default long getActiveFlowRuleCount(DeviceId deviceId) { return 0; } diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java index 449a1fdf8b..07493a887a 100644 --- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java +++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleStore.java @@ -44,6 +44,17 @@ public interface FlowRuleStore extends Store getFlowEntries(DeviceId deviceId) { checkPermission(FLOWRULE_READ); diff --git a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java index 450201695c..13fa3a4600 100644 --- a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java +++ b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java @@ -33,6 +33,8 @@ import java.util.stream.Collectors; import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.google.common.collect.Streams; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; @@ -189,6 +191,7 @@ public class ECFlowRuleStore .register(KryoNamespaces.API) .register(BucketId.class) .register(FlowBucket.class) + .register(ImmutablePair.class) .build()); protected final KryoNamespace.Builder serializerBuilder = KryoNamespace.newBuilder() @@ -316,8 +319,11 @@ public class ECFlowRuleStore GET_FLOW_ENTRY, serializer::decode, flowTable::getFlowEntry, serializer::encode, executor); clusterCommunicator.addSubscriber( GET_DEVICE_FLOW_ENTRIES, serializer::decode, flowTable::getFlowEntries, serializer::encode, executor); - clusterCommunicator.addSubscriber( - GET_DEVICE_FLOW_COUNT, serializer::decode, flowTable::getFlowRuleCount, serializer::encode, executor); + clusterCommunicator., Integer>addSubscriber( + GET_DEVICE_FLOW_COUNT, + serializer::decode, + p -> flowTable.getFlowRuleCount(p.getLeft(), p.getRight()), + serializer::encode, executor); clusterCommunicator.addSubscriber( REMOVE_FLOW_ENTRY, serializer::decode, this::removeFlowRuleInternal, serializer::encode, executor); } @@ -346,6 +352,11 @@ public class ECFlowRuleStore @Override public int getFlowRuleCount(DeviceId deviceId) { + return getFlowRuleCount(deviceId, null); + } + + @Override + public int getFlowRuleCount(DeviceId deviceId, FlowEntryState state) { NodeId master = mastershipService.getMasterFor(deviceId); if (master == null) { log.debug("Failed to getFlowRuleCount: No master for {}", deviceId); @@ -353,19 +364,19 @@ public class ECFlowRuleStore } if (Objects.equals(local, master)) { - return flowTable.getFlowRuleCount(deviceId); + return flowTable.getFlowRuleCount(deviceId, state); } log.trace("Forwarding getFlowRuleCount to master {} for device {}", master, deviceId); return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive( - deviceId, - GET_DEVICE_FLOW_COUNT, - serializer::encode, - serializer::decode, - master), - FLOW_RULE_STORE_TIMEOUT_MILLIS, - TimeUnit.MILLISECONDS, - 0); + Pair.of(deviceId, state), + GET_DEVICE_FLOW_COUNT, + serializer::encode, + serializer::decode, + master), + FLOW_RULE_STORE_TIMEOUT_MILLIS, + TimeUnit.MILLISECONDS, + 0); } @Override @@ -743,6 +754,23 @@ public class ECFlowRuleStore return getFlowTable(deviceId).count(); } + /** + * Returns the count of flow rules in the given state for the given device. + * + * @param deviceId the device for which to return the flow rule count + * @return the flow rule count for the given device + */ + public int getFlowRuleCount(DeviceId deviceId, FlowEntryState state) { + if (state == null) { + return getFlowRuleCount(deviceId); + } + return (int) getFlowTable(deviceId) + .getFlowEntries() + .stream() + .filter(rule -> rule.state() == state) + .count(); + } + /** * Returns the flow entry for the given rule. * @@ -986,4 +1014,14 @@ public class ECFlowRuleStore mastershipTermLifecycles.removeListener(this); } } + + private static class CountMessage { + private final DeviceId deviceId; + private final FlowEntryState state; + + CountMessage(DeviceId deviceId, FlowEntryState state) { + this.deviceId = deviceId; + this.state = state; + } + } } \ No newline at end of file diff --git a/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java index 966718278d..c38d5f8aad 100644 --- a/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java +++ b/web/api/src/main/java/org/onosproject/rest/resources/StatisticsWebResource.java @@ -38,6 +38,7 @@ import org.onosproject.net.Link; import org.onosproject.net.PortNumber; import org.onosproject.net.device.DeviceService; import org.onosproject.net.device.PortStatistics; +import org.onosproject.net.flow.FlowEntry; import org.onosproject.net.flow.FlowRuleService; import org.onosproject.net.flow.TableStatisticsEntry; import org.onosproject.net.link.LinkService; @@ -346,7 +347,7 @@ public class StatisticsWebResource extends AbstractWebResource { final ObjectNode root = mapper().createObjectNode(); final ArrayNode rootArrayNode = root.putArray("statistics"); for (final Device device : devices) { - long activeEntries = service.getActiveFlowRuleCount(device.id()); + int activeEntries = service.getFlowRuleCount(device.id(), FlowEntry.FlowEntryState.ADDED); final ObjectNode entry = mapper().createObjectNode(); entry.put("device", device.id().toString()); entry.put("activeEntries", activeEntries);