Optimize filtering flow rule counts by state

Change-Id: I1e1d80b8e618743ee449162a081cf42e71c99abf
This commit is contained in:
Jordan Halterman 2019-03-04 18:12:20 -08:00 committed by Charles Chan
parent bd609c0aae
commit fd86fa6e41
6 changed files with 93 additions and 14 deletions

View File

@ -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.
*

View File

@ -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;
}

View File

@ -44,6 +44,17 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
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 stored flow.
*
@ -154,6 +165,8 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
*
* @param deviceId the device ID
* @return number of flow rules in ADDED state
* @deprecated since 2.1
*/
@Deprecated
long getActiveFlowRuleCount(DeviceId deviceId);
}

View File

@ -248,6 +248,13 @@ public class FlowRuleManager
return store.getFlowRuleCount(deviceId);
}
@Override
public int getFlowRuleCount(DeviceId deviceId, FlowEntry.FlowEntryState state) {
checkPermission(FLOWRULE_READ);
checkNotNull(deviceId, "Device ID cannot be null");
return store.getFlowRuleCount(deviceId, state);
}
@Override
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
checkPermission(FLOWRULE_READ);

View File

@ -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.<Pair<DeviceId, FlowEntryState>, 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;
}
}
}

View File

@ -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);