Committed by
Gerrit Code Review
CORD-13:Table Statistics support along with CLI and REST
Change-Id: Ic7facc73754c4b1e7c9c5a9eecd217f89a67e135
Showing
18 changed files
with
721 additions
and
9 deletions
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.onosproject.cli.net; | ||
| 17 | + | ||
| 18 | +import static com.google.common.collect.Lists.newArrayList; | ||
| 19 | + | ||
| 20 | +import java.util.Collections; | ||
| 21 | +import java.util.List; | ||
| 22 | +import java.util.Map; | ||
| 23 | +import java.util.SortedMap; | ||
| 24 | +import java.util.TreeMap; | ||
| 25 | + | ||
| 26 | +import org.apache.karaf.shell.commands.Argument; | ||
| 27 | +import org.apache.karaf.shell.commands.Command; | ||
| 28 | +import org.apache.karaf.shell.commands.Option; | ||
| 29 | +import org.onosproject.cli.AbstractShellCommand; | ||
| 30 | +import org.onosproject.cli.Comparators; | ||
| 31 | +import org.onosproject.net.Device; | ||
| 32 | +import org.onosproject.net.DeviceId; | ||
| 33 | +import org.onosproject.net.device.DeviceService; | ||
| 34 | +import org.onosproject.net.flow.FlowRuleService; | ||
| 35 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 36 | + | ||
| 37 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 38 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 39 | +import com.fasterxml.jackson.databind.node.ArrayNode; | ||
| 40 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 41 | + | ||
| 42 | +/** | ||
| 43 | + * Lists port statistic of all ports in the system. | ||
| 44 | + */ | ||
| 45 | +@Command(scope = "onos", name = "tablestats", | ||
| 46 | + description = "Lists statistics of all tables in the device") | ||
| 47 | +public class TableStatisticsCommand extends AbstractShellCommand { | ||
| 48 | + | ||
| 49 | + @Option(name = "-t", aliases = "--table", description = "Show human readable table format for statistics", | ||
| 50 | + required = false, multiValued = false) | ||
| 51 | + private boolean table = false; | ||
| 52 | + | ||
| 53 | + @Argument(index = 0, name = "uri", description = "Device ID", | ||
| 54 | + required = false, multiValued = false) | ||
| 55 | + String uri = null; | ||
| 56 | + | ||
| 57 | + private static final String FORMAT = | ||
| 58 | + " table=%s, active=%s, lookedup=%s, matched=%s"; | ||
| 59 | + | ||
| 60 | + @Override | ||
| 61 | + protected void execute() { | ||
| 62 | + FlowRuleService flowService = get(FlowRuleService.class); | ||
| 63 | + DeviceService deviceService = get(DeviceService.class); | ||
| 64 | + | ||
| 65 | + SortedMap<Device, List<TableStatisticsEntry>> deviceTableStats = | ||
| 66 | + getSortedTableStats(deviceService, flowService); | ||
| 67 | + | ||
| 68 | + if (outputJson()) { | ||
| 69 | + print("%s", json(deviceTableStats.keySet(), deviceTableStats)); | ||
| 70 | + } else { | ||
| 71 | + deviceTableStats.forEach((device, tableStats) -> printTableStats(device, tableStats)); | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + /** | ||
| 76 | + * Produces a JSON array of table statistics grouped by the each device. | ||
| 77 | + * | ||
| 78 | + * @param devices collection of devices | ||
| 79 | + * @param deviceTableStats collection of table statistics per each device | ||
| 80 | + * @return JSON array | ||
| 81 | + */ | ||
| 82 | + private JsonNode json(Iterable<Device> devices, | ||
| 83 | + Map<Device, List<TableStatisticsEntry>> deviceTableStats) { | ||
| 84 | + ObjectMapper mapper = new ObjectMapper(); | ||
| 85 | + ArrayNode result = mapper.createArrayNode(); | ||
| 86 | + for (Device device : devices) { | ||
| 87 | + result.add(json(mapper, device, deviceTableStats.get(device))); | ||
| 88 | + } | ||
| 89 | + return result; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + // Produces JSON object with the table statistics of the given device. | ||
| 93 | + private ObjectNode json(ObjectMapper mapper, | ||
| 94 | + Device device, List<TableStatisticsEntry> tableStats) { | ||
| 95 | + ObjectNode result = mapper.createObjectNode(); | ||
| 96 | + ArrayNode array = mapper.createArrayNode(); | ||
| 97 | + | ||
| 98 | + tableStats.forEach(tableStat -> array.add(jsonForEntity(tableStat, TableStatisticsEntry.class))); | ||
| 99 | + | ||
| 100 | + result.put("device", device.id().toString()) | ||
| 101 | + .put("tableCount", tableStats.size()) | ||
| 102 | + .set("tables", array); | ||
| 103 | + return result; | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + /** | ||
| 107 | + * Prints flow table statistics. | ||
| 108 | + * | ||
| 109 | + * @param d the device | ||
| 110 | + * @param tableStats the set of flow table statistics for that device | ||
| 111 | + */ | ||
| 112 | + protected void printTableStats(Device d, | ||
| 113 | + List<TableStatisticsEntry> tableStats) { | ||
| 114 | + boolean empty = tableStats == null || tableStats.isEmpty(); | ||
| 115 | + print("deviceId=%s, tableCount=%d", d.id(), empty ? 0 : tableStats.size()); | ||
| 116 | + if (!empty) { | ||
| 117 | + for (TableStatisticsEntry t : tableStats) { | ||
| 118 | + print(FORMAT, t.tableId(), t.activeFlowEntries(), | ||
| 119 | + t.packetsLookedup(), t.packetsMatched()); | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + /** | ||
| 125 | + * Returns the list of table statistics sorted using the device ID URIs and table IDs. | ||
| 126 | + * | ||
| 127 | + * @param deviceService device service | ||
| 128 | + * @param flowService flow rule service | ||
| 129 | + * @return sorted table statistics list | ||
| 130 | + */ | ||
| 131 | + protected SortedMap<Device, List<TableStatisticsEntry>> getSortedTableStats(DeviceService deviceService, | ||
| 132 | + FlowRuleService flowService) { | ||
| 133 | + SortedMap<Device, List<TableStatisticsEntry>> deviceTableStats = new TreeMap<>(Comparators.ELEMENT_COMPARATOR); | ||
| 134 | + List<TableStatisticsEntry> tableStatsList; | ||
| 135 | + Iterable<Device> devices = uri == null ? deviceService.getDevices() : | ||
| 136 | + Collections.singletonList(deviceService.getDevice(DeviceId.deviceId(uri))); | ||
| 137 | + for (Device d : devices) { | ||
| 138 | + tableStatsList = newArrayList(flowService.getFlowTableStatistics(d.id())); | ||
| 139 | + tableStatsList.sort((p1, p2) -> Integer.valueOf(p1.tableId()).compareTo(Integer.valueOf(p2.tableId()))); | ||
| 140 | + deviceTableStats.put(d, tableStatsList); | ||
| 141 | + } | ||
| 142 | + return deviceTableStats; | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | +} |
| ... | @@ -348,6 +348,10 @@ | ... | @@ -348,6 +348,10 @@ |
| 348 | </command> | 348 | </command> |
| 349 | 349 | ||
| 350 | <command> | 350 | <command> |
| 351 | + <action class="org.onosproject.cli.net.TableStatisticsCommand"/> | ||
| 352 | + </command> | ||
| 353 | + | ||
| 354 | + <command> | ||
| 351 | <action class="org.onosproject.cli.net.FlowsListCommand"/> | 355 | <action class="org.onosproject.cli.net.FlowsListCommand"/> |
| 352 | <completers> | 356 | <completers> |
| 353 | <ref component-id="flowRuleStatusCompleter"/> | 357 | <ref component-id="flowRuleStatusCompleter"/> | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.onosproject.net.flow; | ||
| 17 | + | ||
| 18 | +import org.onosproject.net.DeviceId; | ||
| 19 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 20 | + | ||
| 21 | +/** | ||
| 22 | + * Default implementation of table statistics entry interface. | ||
| 23 | + */ | ||
| 24 | +public final class DefaultTableStatisticsEntry implements TableStatisticsEntry { | ||
| 25 | + | ||
| 26 | + private final DeviceId deviceId; | ||
| 27 | + private final int tableId; | ||
| 28 | + private final long activeFlowEntries; | ||
| 29 | + private final long packetsLookedupCount; | ||
| 30 | + private final long packetsMatchedCount; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Default table statistics constructor. | ||
| 34 | + * | ||
| 35 | + * @param deviceId device identifier | ||
| 36 | + * @param tableId table identifier | ||
| 37 | + * @param activeFlowEntries number of active flow entries in the table | ||
| 38 | + * @param packetsLookedupCount number of packets looked up in table | ||
| 39 | + * @param packetsMatchedCount number of packets that hit table | ||
| 40 | + */ | ||
| 41 | + public DefaultTableStatisticsEntry(DeviceId deviceId, | ||
| 42 | + int tableId, | ||
| 43 | + long activeFlowEntries, | ||
| 44 | + long packetsLookedupCount, | ||
| 45 | + long packetsMatchedCount) { | ||
| 46 | + this.deviceId = checkNotNull(deviceId); | ||
| 47 | + this.tableId = tableId; | ||
| 48 | + this.activeFlowEntries = activeFlowEntries; | ||
| 49 | + this.packetsLookedupCount = packetsLookedupCount; | ||
| 50 | + this.packetsMatchedCount = packetsMatchedCount; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public String toString() { | ||
| 55 | + StringBuilder sb = new StringBuilder("device: " + deviceId + ", "); | ||
| 56 | + | ||
| 57 | + sb.append("tableId: " + this.tableId + ", "); | ||
| 58 | + sb.append("activeEntries: " + this.activeFlowEntries + ", "); | ||
| 59 | + sb.append("packetsLookedUp: " + this.packetsLookedupCount + ", "); | ||
| 60 | + sb.append("packetsMatched: " + this.packetsMatchedCount); | ||
| 61 | + | ||
| 62 | + return sb.toString(); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + @Override | ||
| 66 | + public int tableId() { | ||
| 67 | + return tableId; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @Override | ||
| 71 | + public long activeFlowEntries() { | ||
| 72 | + return activeFlowEntries; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public long packetsLookedup() { | ||
| 77 | + return packetsLookedupCount; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @Override | ||
| 81 | + public long packetsMatched() { | ||
| 82 | + return packetsMatchedCount; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + @Override | ||
| 86 | + public DeviceId deviceId() { | ||
| 87 | + return deviceId; | ||
| 88 | + } | ||
| 89 | +} |
| ... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
| 17 | 17 | ||
| 18 | +import java.util.List; | ||
| 19 | + | ||
| 18 | import org.onosproject.net.DeviceId; | 20 | import org.onosproject.net.DeviceId; |
| 19 | import org.onosproject.net.provider.ProviderService; | 21 | import org.onosproject.net.provider.ProviderService; |
| 20 | 22 | ||
| ... | @@ -50,6 +52,15 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide | ... | @@ -50,6 +52,15 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide |
| 50 | void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries); | 52 | void pushFlowMetricsWithoutFlowMissing(DeviceId deviceId, Iterable<FlowEntry> flowEntries); |
| 51 | 53 | ||
| 52 | /** | 54 | /** |
| 55 | + * Pushes the collection of table statistics entries currently extracted | ||
| 56 | + * from the given device. | ||
| 57 | + * | ||
| 58 | + * @param deviceId device identifier | ||
| 59 | + * @param tableStatsEntries collection of flow table statistics entries | ||
| 60 | + */ | ||
| 61 | + void pushTableStatistics(DeviceId deviceId, List<TableStatisticsEntry> tableStatsEntries); | ||
| 62 | + | ||
| 63 | + /** | ||
| 53 | * Indicates to the core that the requested batch operation has | 64 | * Indicates to the core that the requested batch operation has |
| 54 | * been completed. | 65 | * been completed. |
| 55 | * | 66 | * |
| ... | @@ -57,5 +68,4 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide | ... | @@ -57,5 +68,4 @@ public interface FlowRuleProviderService extends ProviderService<FlowRuleProvide |
| 57 | * @param operation the resulting outcome of the operation | 68 | * @param operation the resulting outcome of the operation |
| 58 | */ | 69 | */ |
| 59 | void batchOperationCompleted(long batchId, CompletedBatchOperation operation); | 70 | void batchOperationCompleted(long batchId, CompletedBatchOperation operation); |
| 60 | - | ||
| 61 | } | 71 | } | ... | ... |
| ... | @@ -104,4 +104,11 @@ public interface FlowRuleService | ... | @@ -104,4 +104,11 @@ public interface FlowRuleService |
| 104 | */ | 104 | */ |
| 105 | void apply(FlowRuleOperations ops); | 105 | void apply(FlowRuleOperations ops); |
| 106 | 106 | ||
| 107 | + /** | ||
| 108 | + * Returns the collection of flow table statistics of the specified device. | ||
| 109 | + * | ||
| 110 | + * @param deviceId device identifier | ||
| 111 | + * @return collection of flow table statistics | ||
| 112 | + */ | ||
| 113 | + Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId); | ||
| 107 | } | 114 | } | ... | ... |
| ... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.net.flow; | 16 | package org.onosproject.net.flow; |
| 17 | 17 | ||
| 18 | +import java.util.List; | ||
| 19 | + | ||
| 18 | import org.onosproject.net.DeviceId; | 20 | import org.onosproject.net.DeviceId; |
| 19 | import org.onosproject.store.Store; | 21 | import org.onosproject.store.Store; |
| 20 | 22 | ||
| ... | @@ -93,4 +95,23 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe | ... | @@ -93,4 +95,23 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe |
| 93 | * @return flow_removed event, or null if nothing removed | 95 | * @return flow_removed event, or null if nothing removed |
| 94 | */ | 96 | */ |
| 95 | FlowRuleEvent removeFlowRule(FlowEntry rule); | 97 | FlowRuleEvent removeFlowRule(FlowEntry rule); |
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * Updates the flow table statistics of the specified device using | ||
| 101 | + * the given statistics. | ||
| 102 | + * | ||
| 103 | + * @param deviceId device identifier | ||
| 104 | + * @param tableStats list of table statistics | ||
| 105 | + * @return ready to send event describing what occurred; | ||
| 106 | + */ | ||
| 107 | + FlowRuleEvent updateTableStatistics(DeviceId deviceId, | ||
| 108 | + List<TableStatisticsEntry> tableStats); | ||
| 109 | + | ||
| 110 | + /** | ||
| 111 | + * Returns the flow table statistics associated with a device. | ||
| 112 | + * | ||
| 113 | + * @param deviceId the device ID | ||
| 114 | + * @return the flow table statistics | ||
| 115 | + */ | ||
| 116 | + Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId); | ||
| 96 | } | 117 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.onosproject.net.flow; | ||
| 17 | + | ||
| 18 | +import org.onosproject.net.DeviceId; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * Interface for flow table statistics of a device. | ||
| 22 | + */ | ||
| 23 | +public interface TableStatisticsEntry { | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * Returns the device Id. | ||
| 27 | + * | ||
| 28 | + * @return device id | ||
| 29 | + */ | ||
| 30 | + DeviceId deviceId(); | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Returns the table number. | ||
| 34 | + * | ||
| 35 | + * @return table number | ||
| 36 | + */ | ||
| 37 | + int tableId(); | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Returns the number of active flow entries in this table. | ||
| 41 | + * | ||
| 42 | + * @return the number of active flow entries | ||
| 43 | + */ | ||
| 44 | + long activeFlowEntries(); | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * Returns the number of packets looked up in the table. | ||
| 48 | + * | ||
| 49 | + * @return the number of packets looked up in the table | ||
| 50 | + */ | ||
| 51 | + long packetsLookedup(); | ||
| 52 | + | ||
| 53 | + /** | ||
| 54 | + * Returns the number of packets that successfully matched in the table. | ||
| 55 | + * | ||
| 56 | + * @return the number of packets that successfully matched in the table | ||
| 57 | + */ | ||
| 58 | + long packetsMatched(); | ||
| 59 | +} |
| ... | @@ -35,17 +35,14 @@ public class FlowRuleServiceAdapter implements FlowRuleService { | ... | @@ -35,17 +35,14 @@ public class FlowRuleServiceAdapter implements FlowRuleService { |
| 35 | 35 | ||
| 36 | @Override | 36 | @Override |
| 37 | public void applyFlowRules(FlowRule... flowRules) { | 37 | public void applyFlowRules(FlowRule... flowRules) { |
| 38 | - | ||
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | @Override | 40 | @Override |
| 42 | public void removeFlowRules(FlowRule... flowRules) { | 41 | public void removeFlowRules(FlowRule... flowRules) { |
| 43 | - | ||
| 44 | } | 42 | } |
| 45 | 43 | ||
| 46 | @Override | 44 | @Override |
| 47 | public void removeFlowRulesById(ApplicationId appId) { | 45 | public void removeFlowRulesById(ApplicationId appId) { |
| 48 | - | ||
| 49 | } | 46 | } |
| 50 | 47 | ||
| 51 | @Override | 48 | @Override |
| ... | @@ -60,16 +57,18 @@ public class FlowRuleServiceAdapter implements FlowRuleService { | ... | @@ -60,16 +57,18 @@ public class FlowRuleServiceAdapter implements FlowRuleService { |
| 60 | 57 | ||
| 61 | @Override | 58 | @Override |
| 62 | public void apply(FlowRuleOperations ops) { | 59 | public void apply(FlowRuleOperations ops) { |
| 63 | - | ||
| 64 | } | 60 | } |
| 65 | 61 | ||
| 66 | @Override | 62 | @Override |
| 67 | public void addListener(FlowRuleListener listener) { | 63 | public void addListener(FlowRuleListener listener) { |
| 68 | - | ||
| 69 | } | 64 | } |
| 70 | 65 | ||
| 71 | @Override | 66 | @Override |
| 72 | public void removeListener(FlowRuleListener listener) { | 67 | public void removeListener(FlowRuleListener listener) { |
| 68 | + } | ||
| 73 | 69 | ||
| 70 | + @Override | ||
| 71 | + public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) { | ||
| 72 | + return null; | ||
| 74 | } | 73 | } |
| 75 | } | 74 | } | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onosproject.codec.impl; | 16 | package org.onosproject.codec.impl; |
| 17 | 17 | ||
| 18 | import com.google.common.collect.ImmutableSet; | 18 | import com.google.common.collect.ImmutableSet; |
| 19 | + | ||
| 19 | import org.apache.felix.scr.annotations.Activate; | 20 | import org.apache.felix.scr.annotations.Activate; |
| 20 | import org.apache.felix.scr.annotations.Component; | 21 | import org.apache.felix.scr.annotations.Component; |
| 21 | import org.apache.felix.scr.annotations.Deactivate; | 22 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -36,6 +37,7 @@ import org.onosproject.net.Port; | ... | @@ -36,6 +37,7 @@ import org.onosproject.net.Port; |
| 36 | import org.onosproject.net.driver.Driver; | 37 | import org.onosproject.net.driver.Driver; |
| 37 | import org.onosproject.net.flow.FlowEntry; | 38 | import org.onosproject.net.flow.FlowEntry; |
| 38 | import org.onosproject.net.flow.FlowRule; | 39 | import org.onosproject.net.flow.FlowRule; |
| 40 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 39 | import org.onosproject.net.flow.TrafficSelector; | 41 | import org.onosproject.net.flow.TrafficSelector; |
| 40 | import org.onosproject.net.flow.TrafficTreatment; | 42 | import org.onosproject.net.flow.TrafficTreatment; |
| 41 | import org.onosproject.net.flow.criteria.Criterion; | 43 | import org.onosproject.net.flow.criteria.Criterion; |
| ... | @@ -99,6 +101,7 @@ public class CodecManager implements CodecService { | ... | @@ -99,6 +101,7 @@ public class CodecManager implements CodecService { |
| 99 | registerCodec(Driver.class, new DriverCodec()); | 101 | registerCodec(Driver.class, new DriverCodec()); |
| 100 | registerCodec(GroupBucket.class, new GroupBucketCodec()); | 102 | registerCodec(GroupBucket.class, new GroupBucketCodec()); |
| 101 | registerCodec(Load.class, new LoadCodec()); | 103 | registerCodec(Load.class, new LoadCodec()); |
| 104 | + registerCodec(TableStatisticsEntry.class, new TableStatisticsEntryCodec()); | ||
| 102 | log.info("Started"); | 105 | log.info("Started"); |
| 103 | } | 106 | } |
| 104 | 107 | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.onosproject.codec.impl; | ||
| 17 | + | ||
| 18 | +import org.onosproject.codec.CodecContext; | ||
| 19 | +import org.onosproject.codec.JsonCodec; | ||
| 20 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 21 | + | ||
| 22 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| 23 | + | ||
| 24 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 25 | + | ||
| 26 | +/** | ||
| 27 | + * Table statistics entry JSON codec. | ||
| 28 | + */ | ||
| 29 | +public final class TableStatisticsEntryCodec extends JsonCodec<TableStatisticsEntry> { | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public ObjectNode encode(TableStatisticsEntry entry, CodecContext context) { | ||
| 33 | + checkNotNull(entry, "Table Statistics entry cannot be null"); | ||
| 34 | + | ||
| 35 | + final ObjectNode result = context.mapper().createObjectNode() | ||
| 36 | + .put("tableId", entry.tableId()) | ||
| 37 | + .put("deviceId", entry.deviceId().toString()) | ||
| 38 | + .put("activeEntries", entry.activeFlowEntries()) | ||
| 39 | + .put("packetsLookedUp", entry.packetsLookedup()) | ||
| 40 | + .put("packetsMatched", entry.packetsMatched()); | ||
| 41 | + | ||
| 42 | + return result; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | +} | ||
| 46 | + |
| ... | @@ -20,8 +20,10 @@ import com.google.common.cache.CacheBuilder; | ... | @@ -20,8 +20,10 @@ import com.google.common.cache.CacheBuilder; |
| 20 | import com.google.common.cache.RemovalListener; | 20 | import com.google.common.cache.RemovalListener; |
| 21 | import com.google.common.cache.RemovalNotification; | 21 | import com.google.common.cache.RemovalNotification; |
| 22 | import com.google.common.collect.FluentIterable; | 22 | import com.google.common.collect.FluentIterable; |
| 23 | +import com.google.common.collect.ImmutableList; | ||
| 23 | import com.google.common.collect.Sets; | 24 | import com.google.common.collect.Sets; |
| 24 | import com.google.common.util.concurrent.SettableFuture; | 25 | import com.google.common.util.concurrent.SettableFuture; |
| 26 | + | ||
| 25 | import org.apache.felix.scr.annotations.Activate; | 27 | import org.apache.felix.scr.annotations.Activate; |
| 26 | import org.apache.felix.scr.annotations.Component; | 28 | import org.apache.felix.scr.annotations.Component; |
| 27 | import org.apache.felix.scr.annotations.Deactivate; | 29 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -44,6 +46,7 @@ import org.onosproject.net.flow.FlowRuleEvent.Type; | ... | @@ -44,6 +46,7 @@ import org.onosproject.net.flow.FlowRuleEvent.Type; |
| 44 | import org.onosproject.net.flow.FlowRuleStore; | 46 | import org.onosproject.net.flow.FlowRuleStore; |
| 45 | import org.onosproject.net.flow.FlowRuleStoreDelegate; | 47 | import org.onosproject.net.flow.FlowRuleStoreDelegate; |
| 46 | import org.onosproject.net.flow.StoredFlowEntry; | 48 | import org.onosproject.net.flow.StoredFlowEntry; |
| 49 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 47 | import org.onosproject.store.AbstractStore; | 50 | import org.onosproject.store.AbstractStore; |
| 48 | import org.slf4j.Logger; | 51 | import org.slf4j.Logger; |
| 49 | 52 | ||
| ... | @@ -79,6 +82,9 @@ public class SimpleFlowRuleStore | ... | @@ -79,6 +82,9 @@ public class SimpleFlowRuleStore |
| 79 | private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, List<StoredFlowEntry>>> | 82 | private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, List<StoredFlowEntry>>> |
| 80 | flowEntries = new ConcurrentHashMap<>(); | 83 | flowEntries = new ConcurrentHashMap<>(); |
| 81 | 84 | ||
| 85 | + private final ConcurrentMap<DeviceId, List<TableStatisticsEntry>> | ||
| 86 | + deviceTableStats = new ConcurrentHashMap<>(); | ||
| 87 | + | ||
| 82 | private final AtomicInteger localBatchIdGen = new AtomicInteger(); | 88 | private final AtomicInteger localBatchIdGen = new AtomicInteger(); |
| 83 | 89 | ||
| 84 | // TODO: make this configurable | 90 | // TODO: make this configurable |
| ... | @@ -97,6 +103,7 @@ public class SimpleFlowRuleStore | ... | @@ -97,6 +103,7 @@ public class SimpleFlowRuleStore |
| 97 | 103 | ||
| 98 | @Deactivate | 104 | @Deactivate |
| 99 | public void deactivate() { | 105 | public void deactivate() { |
| 106 | + deviceTableStats.clear(); | ||
| 100 | flowEntries.clear(); | 107 | flowEntries.clear(); |
| 101 | log.info("Stopped"); | 108 | log.info("Stopped"); |
| 102 | } | 109 | } |
| ... | @@ -315,4 +322,20 @@ public class SimpleFlowRuleStore | ... | @@ -315,4 +322,20 @@ public class SimpleFlowRuleStore |
| 315 | } | 322 | } |
| 316 | } | 323 | } |
| 317 | } | 324 | } |
| 325 | + | ||
| 326 | + @Override | ||
| 327 | + public FlowRuleEvent updateTableStatistics(DeviceId deviceId, | ||
| 328 | + List<TableStatisticsEntry> tableStats) { | ||
| 329 | + deviceTableStats.put(deviceId, tableStats); | ||
| 330 | + return null; | ||
| 331 | + } | ||
| 332 | + | ||
| 333 | + @Override | ||
| 334 | + public Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId) { | ||
| 335 | + List<TableStatisticsEntry> tableStats = deviceTableStats.get(deviceId); | ||
| 336 | + if (tableStats == null) { | ||
| 337 | + return Collections.emptyList(); | ||
| 338 | + } | ||
| 339 | + return ImmutableList.copyOf(tableStats); | ||
| 340 | + } | ||
| 318 | } | 341 | } | ... | ... |
| ... | @@ -22,6 +22,7 @@ import com.google.common.collect.Lists; | ... | @@ -22,6 +22,7 @@ import com.google.common.collect.Lists; |
| 22 | import com.google.common.collect.Maps; | 22 | import com.google.common.collect.Maps; |
| 23 | import com.google.common.collect.Multimap; | 23 | import com.google.common.collect.Multimap; |
| 24 | import com.google.common.collect.Sets; | 24 | import com.google.common.collect.Sets; |
| 25 | + | ||
| 25 | import org.apache.felix.scr.annotations.Activate; | 26 | import org.apache.felix.scr.annotations.Activate; |
| 26 | import org.apache.felix.scr.annotations.Component; | 27 | import org.apache.felix.scr.annotations.Component; |
| 27 | import org.apache.felix.scr.annotations.Deactivate; | 28 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -58,6 +59,7 @@ import org.onosproject.net.flow.FlowRuleProviderService; | ... | @@ -58,6 +59,7 @@ import org.onosproject.net.flow.FlowRuleProviderService; |
| 58 | import org.onosproject.net.flow.FlowRuleService; | 59 | import org.onosproject.net.flow.FlowRuleService; |
| 59 | import org.onosproject.net.flow.FlowRuleStore; | 60 | import org.onosproject.net.flow.FlowRuleStore; |
| 60 | import org.onosproject.net.flow.FlowRuleStoreDelegate; | 61 | import org.onosproject.net.flow.FlowRuleStoreDelegate; |
| 62 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 61 | import org.onosproject.net.provider.AbstractProviderService; | 63 | import org.onosproject.net.provider.AbstractProviderService; |
| 62 | import org.osgi.service.component.ComponentContext; | 64 | import org.osgi.service.component.ComponentContext; |
| 63 | import org.slf4j.Logger; | 65 | import org.slf4j.Logger; |
| ... | @@ -448,6 +450,12 @@ public class FlowRuleManager | ... | @@ -448,6 +450,12 @@ public class FlowRuleManager |
| 448 | operation | 450 | operation |
| 449 | )); | 451 | )); |
| 450 | } | 452 | } |
| 453 | + | ||
| 454 | + @Override | ||
| 455 | + public void pushTableStatistics(DeviceId deviceId, | ||
| 456 | + List<TableStatisticsEntry> tableStats) { | ||
| 457 | + store.updateTableStatistics(deviceId, tableStats); | ||
| 458 | + } | ||
| 451 | } | 459 | } |
| 452 | 460 | ||
| 453 | // Store delegate to re-post events emitted from the store. | 461 | // Store delegate to re-post events emitted from the store. |
| ... | @@ -603,4 +611,10 @@ public class FlowRuleManager | ... | @@ -603,4 +611,10 @@ public class FlowRuleManager |
| 603 | } | 611 | } |
| 604 | 612 | ||
| 605 | } | 613 | } |
| 614 | + | ||
| 615 | + @Override | ||
| 616 | + public Iterable<TableStatisticsEntry> getFlowTableStatistics(DeviceId deviceId) { | ||
| 617 | + checkPermission(FLOWRULE_READ); | ||
| 618 | + return store.getTableStatistics(deviceId); | ||
| 619 | + } | ||
| 606 | } | 620 | } | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | package org.onosproject.store.flow.impl; | 16 | package org.onosproject.store.flow.impl; |
| 17 | 17 | ||
| 18 | import com.google.common.base.Objects; | 18 | import com.google.common.base.Objects; |
| 19 | +import com.google.common.collect.ImmutableList; | ||
| 19 | import com.google.common.collect.ImmutableMap; | 20 | import com.google.common.collect.ImmutableMap; |
| 20 | import com.google.common.collect.Iterables; | 21 | import com.google.common.collect.Iterables; |
| 21 | import com.google.common.collect.Maps; | 22 | import com.google.common.collect.Maps; |
| ... | @@ -57,6 +58,7 @@ import org.onosproject.net.flow.FlowRuleService; | ... | @@ -57,6 +58,7 @@ import org.onosproject.net.flow.FlowRuleService; |
| 57 | import org.onosproject.net.flow.FlowRuleStore; | 58 | import org.onosproject.net.flow.FlowRuleStore; |
| 58 | import org.onosproject.net.flow.FlowRuleStoreDelegate; | 59 | import org.onosproject.net.flow.FlowRuleStoreDelegate; |
| 59 | import org.onosproject.net.flow.StoredFlowEntry; | 60 | import org.onosproject.net.flow.StoredFlowEntry; |
| 61 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 60 | import org.onosproject.store.AbstractStore; | 62 | import org.onosproject.store.AbstractStore; |
| 61 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 63 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
| 62 | import org.onosproject.store.cluster.messaging.ClusterMessage; | 64 | import org.onosproject.store.cluster.messaging.ClusterMessage; |
| ... | @@ -64,9 +66,16 @@ import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | ... | @@ -64,9 +66,16 @@ import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
| 64 | import org.onosproject.store.flow.ReplicaInfoEvent; | 66 | import org.onosproject.store.flow.ReplicaInfoEvent; |
| 65 | import org.onosproject.store.flow.ReplicaInfoEventListener; | 67 | import org.onosproject.store.flow.ReplicaInfoEventListener; |
| 66 | import org.onosproject.store.flow.ReplicaInfoService; | 68 | import org.onosproject.store.flow.ReplicaInfoService; |
| 69 | +import org.onosproject.store.impl.MastershipBasedTimestamp; | ||
| 70 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
| 67 | import org.onosproject.store.serializers.KryoSerializer; | 71 | import org.onosproject.store.serializers.KryoSerializer; |
| 68 | import org.onosproject.store.serializers.StoreSerializer; | 72 | import org.onosproject.store.serializers.StoreSerializer; |
| 69 | import org.onosproject.store.serializers.custom.DistributedStoreSerializers; | 73 | import org.onosproject.store.serializers.custom.DistributedStoreSerializers; |
| 74 | +import org.onosproject.store.service.EventuallyConsistentMap; | ||
| 75 | +import org.onosproject.store.service.EventuallyConsistentMapEvent; | ||
| 76 | +import org.onosproject.store.service.EventuallyConsistentMapListener; | ||
| 77 | +import org.onosproject.store.service.StorageService; | ||
| 78 | +import org.onosproject.store.service.WallClockTimestamp; | ||
| 70 | import org.osgi.service.component.ComponentContext; | 79 | import org.osgi.service.component.ComponentContext; |
| 71 | import org.slf4j.Logger; | 80 | import org.slf4j.Logger; |
| 72 | 81 | ||
| ... | @@ -151,6 +160,13 @@ public class NewDistributedFlowRuleStore | ... | @@ -151,6 +160,13 @@ public class NewDistributedFlowRuleStore |
| 151 | private final ScheduledExecutorService backupSenderExecutor = | 160 | private final ScheduledExecutorService backupSenderExecutor = |
| 152 | Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/flow", "backup-sender")); | 161 | Executors.newSingleThreadScheduledExecutor(groupedThreads("onos/flow", "backup-sender")); |
| 153 | 162 | ||
| 163 | + private EventuallyConsistentMap<DeviceId, List<TableStatisticsEntry>> deviceTableStats; | ||
| 164 | + private final EventuallyConsistentMapListener<DeviceId, List<TableStatisticsEntry>> tableStatsListener = | ||
| 165 | + new InternalTableStatsListener(); | ||
| 166 | + | ||
| 167 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 168 | + protected StorageService storageService; | ||
| 169 | + | ||
| 154 | protected static final StoreSerializer SERIALIZER = new KryoSerializer() { | 170 | protected static final StoreSerializer SERIALIZER = new KryoSerializer() { |
| 155 | @Override | 171 | @Override |
| 156 | protected void setupKryoPool() { | 172 | protected void setupKryoPool() { |
| ... | @@ -161,6 +177,11 @@ public class NewDistributedFlowRuleStore | ... | @@ -161,6 +177,11 @@ public class NewDistributedFlowRuleStore |
| 161 | } | 177 | } |
| 162 | }; | 178 | }; |
| 163 | 179 | ||
| 180 | + protected static final KryoNamespace.Builder SERIALIZER_BUILDER = KryoNamespace.newBuilder() | ||
| 181 | + .register(KryoNamespaces.API) | ||
| 182 | + .register(MastershipBasedTimestamp.class); | ||
| 183 | + | ||
| 184 | + | ||
| 164 | private IdGenerator idGenerator; | 185 | private IdGenerator idGenerator; |
| 165 | private NodeId local; | 186 | private NodeId local; |
| 166 | 187 | ||
| ... | @@ -186,6 +207,15 @@ public class NewDistributedFlowRuleStore | ... | @@ -186,6 +207,15 @@ public class NewDistributedFlowRuleStore |
| 186 | TimeUnit.MILLISECONDS); | 207 | TimeUnit.MILLISECONDS); |
| 187 | } | 208 | } |
| 188 | 209 | ||
| 210 | + deviceTableStats = storageService.<DeviceId, List<TableStatisticsEntry>>eventuallyConsistentMapBuilder() | ||
| 211 | + .withName("onos-flow-table-stats") | ||
| 212 | + .withSerializer(SERIALIZER_BUILDER) | ||
| 213 | + .withAntiEntropyPeriod(5, TimeUnit.SECONDS) | ||
| 214 | + .withTimestampProvider((k, v) -> new WallClockTimestamp()) | ||
| 215 | + .withTombstonesDisabled() | ||
| 216 | + .build(); | ||
| 217 | + deviceTableStats.addListener(tableStatsListener); | ||
| 218 | + | ||
| 189 | logConfig("Started"); | 219 | logConfig("Started"); |
| 190 | } | 220 | } |
| 191 | 221 | ||
| ... | @@ -197,6 +227,8 @@ public class NewDistributedFlowRuleStore | ... | @@ -197,6 +227,8 @@ public class NewDistributedFlowRuleStore |
| 197 | } | 227 | } |
| 198 | configService.unregisterProperties(getClass(), false); | 228 | configService.unregisterProperties(getClass(), false); |
| 199 | unregisterMessageHandlers(); | 229 | unregisterMessageHandlers(); |
| 230 | + deviceTableStats.removeListener(tableStatsListener); | ||
| 231 | + deviceTableStats.destroy(); | ||
| 200 | messageHandlingExecutor.shutdownNow(); | 232 | messageHandlingExecutor.shutdownNow(); |
| 201 | backupSenderExecutor.shutdownNow(); | 233 | backupSenderExecutor.shutdownNow(); |
| 202 | log.info("Stopped"); | 234 | log.info("Stopped"); |
| ... | @@ -786,4 +818,36 @@ public class NewDistributedFlowRuleStore | ... | @@ -786,4 +818,36 @@ public class NewDistributedFlowRuleStore |
| 786 | return backedupDevices; | 818 | return backedupDevices; |
| 787 | } | 819 | } |
| 788 | } | 820 | } |
| 821 | + | ||
| 822 | + @Override | ||
| 823 | + public FlowRuleEvent updateTableStatistics(DeviceId deviceId, | ||
| 824 | + List<TableStatisticsEntry> tableStats) { | ||
| 825 | + deviceTableStats.put(deviceId, tableStats); | ||
| 826 | + return null; | ||
| 827 | + } | ||
| 828 | + | ||
| 829 | + @Override | ||
| 830 | + public Iterable<TableStatisticsEntry> getTableStatistics(DeviceId deviceId) { | ||
| 831 | + NodeId master = mastershipService.getMasterFor(deviceId); | ||
| 832 | + | ||
| 833 | + if (master == null) { | ||
| 834 | + log.debug("Failed to getTableStats: No master for {}", deviceId); | ||
| 835 | + return Collections.emptyList(); | ||
| 836 | + } | ||
| 837 | + | ||
| 838 | + List<TableStatisticsEntry> tableStats = deviceTableStats.get(deviceId); | ||
| 839 | + if (tableStats == null) { | ||
| 840 | + return Collections.emptyList(); | ||
| 841 | + } | ||
| 842 | + return ImmutableList.copyOf(tableStats); | ||
| 843 | + } | ||
| 844 | + | ||
| 845 | + private class InternalTableStatsListener | ||
| 846 | + implements EventuallyConsistentMapListener<DeviceId, List<TableStatisticsEntry>> { | ||
| 847 | + @Override | ||
| 848 | + public void event(EventuallyConsistentMapEvent<DeviceId, | ||
| 849 | + List<TableStatisticsEntry>> event) { | ||
| 850 | + //TODO: Generate an event to listeners (do we need?) | ||
| 851 | + } | ||
| 852 | + } | ||
| 789 | } | 853 | } | ... | ... |
| ... | @@ -84,6 +84,7 @@ import org.onosproject.net.device.PortStatistics; | ... | @@ -84,6 +84,7 @@ import org.onosproject.net.device.PortStatistics; |
| 84 | import org.onosproject.net.flow.CompletedBatchOperation; | 84 | import org.onosproject.net.flow.CompletedBatchOperation; |
| 85 | import org.onosproject.net.flow.DefaultFlowEntry; | 85 | import org.onosproject.net.flow.DefaultFlowEntry; |
| 86 | import org.onosproject.net.flow.DefaultFlowRule; | 86 | import org.onosproject.net.flow.DefaultFlowRule; |
| 87 | +import org.onosproject.net.flow.DefaultTableStatisticsEntry; | ||
| 87 | import org.onosproject.net.flow.DefaultTrafficSelector; | 88 | import org.onosproject.net.flow.DefaultTrafficSelector; |
| 88 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 89 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
| 89 | import org.onosproject.net.flow.FlowEntry; | 90 | import org.onosproject.net.flow.FlowEntry; |
| ... | @@ -95,6 +96,7 @@ import org.onosproject.net.flow.FlowRuleBatchRequest; | ... | @@ -95,6 +96,7 @@ import org.onosproject.net.flow.FlowRuleBatchRequest; |
| 95 | import org.onosproject.net.flow.FlowRuleEvent; | 96 | import org.onosproject.net.flow.FlowRuleEvent; |
| 96 | import org.onosproject.net.flow.FlowRuleExtPayLoad; | 97 | import org.onosproject.net.flow.FlowRuleExtPayLoad; |
| 97 | import org.onosproject.net.flow.StoredFlowEntry; | 98 | import org.onosproject.net.flow.StoredFlowEntry; |
| 99 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 98 | import org.onosproject.net.flow.criteria.Criterion; | 100 | import org.onosproject.net.flow.criteria.Criterion; |
| 99 | import org.onosproject.net.flow.criteria.EthCriterion; | 101 | import org.onosproject.net.flow.criteria.EthCriterion; |
| 100 | import org.onosproject.net.flow.criteria.EthTypeCriterion; | 102 | import org.onosproject.net.flow.criteria.EthTypeCriterion; |
| ... | @@ -421,7 +423,9 @@ public final class KryoNamespaces { | ... | @@ -421,7 +423,9 @@ public final class KryoNamespaces { |
| 421 | DefaultAnnotations.class, | 423 | DefaultAnnotations.class, |
| 422 | PortStatistics.class, | 424 | PortStatistics.class, |
| 423 | DefaultPortStatistics.class, | 425 | DefaultPortStatistics.class, |
| 424 | - IntentDomainId.class | 426 | + IntentDomainId.class, |
| 427 | + TableStatisticsEntry.class, | ||
| 428 | + DefaultTableStatisticsEntry.class | ||
| 425 | ) | 429 | ) |
| 426 | .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) | 430 | .register(new DefaultApplicationIdSerializer(), DefaultApplicationId.class) |
| 427 | .register(new URISerializer(), URI.class) | 431 | .register(new URISerializer(), URI.class) | ... | ... |
| ... | @@ -47,6 +47,8 @@ import org.projectfloodlight.openflow.protocol.OFExperimenter; | ... | @@ -47,6 +47,8 @@ import org.projectfloodlight.openflow.protocol.OFExperimenter; |
| 47 | import org.projectfloodlight.openflow.protocol.OFFactories; | 47 | import org.projectfloodlight.openflow.protocol.OFFactories; |
| 48 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; | 48 | import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry; |
| 49 | import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; | 49 | import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; |
| 50 | +import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; | ||
| 51 | +import org.projectfloodlight.openflow.protocol.OFTableStatsReply; | ||
| 50 | import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry; | 52 | import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry; |
| 51 | import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply; | 53 | import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply; |
| 52 | import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry; | 54 | import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry; |
| ... | @@ -129,6 +131,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -129,6 +131,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
| 129 | protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats = | 131 | protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats = |
| 130 | ArrayListMultimap.create(); | 132 | ArrayListMultimap.create(); |
| 131 | 133 | ||
| 134 | + protected Multimap<Dpid, OFTableStatsEntry> fullTableStats = | ||
| 135 | + ArrayListMultimap.create(); | ||
| 136 | + | ||
| 132 | protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats = | 137 | protected Multimap<Dpid, OFGroupStatsEntry> fullGroupStats = |
| 133 | ArrayListMultimap.create(); | 138 | ArrayListMultimap.create(); |
| 134 | 139 | ||
| ... | @@ -230,6 +235,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -230,6 +235,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
| 230 | @Override | 235 | @Override |
| 231 | public void processPacket(Dpid dpid, OFMessage msg) { | 236 | public void processPacket(Dpid dpid, OFMessage msg) { |
| 232 | Collection<OFFlowStatsEntry> flowStats; | 237 | Collection<OFFlowStatsEntry> flowStats; |
| 238 | + Collection<OFTableStatsEntry> tableStats; | ||
| 233 | Collection<OFGroupStatsEntry> groupStats; | 239 | Collection<OFGroupStatsEntry> groupStats; |
| 234 | Collection<OFGroupDescStatsEntry> groupDescStats; | 240 | Collection<OFGroupDescStatsEntry> groupDescStats; |
| 235 | Collection<OFPortStatsEntry> portStats; | 241 | Collection<OFPortStatsEntry> portStats; |
| ... | @@ -277,6 +283,15 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -277,6 +283,15 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
| 277 | executorMsgs.submit(new OFMessageHandler(dpid, rep.build())); | 283 | executorMsgs.submit(new OFMessageHandler(dpid, rep.build())); |
| 278 | } | 284 | } |
| 279 | break; | 285 | break; |
| 286 | + case TABLE: | ||
| 287 | + tableStats = publishTableStats(dpid, (OFTableStatsReply) reply); | ||
| 288 | + if (tableStats != null) { | ||
| 289 | + OFTableStatsReply.Builder rep = | ||
| 290 | + OFFactories.getFactory(msg.getVersion()).buildTableStatsReply(); | ||
| 291 | + rep.setEntries(Lists.newLinkedList(tableStats)); | ||
| 292 | + executorMsgs.submit(new OFMessageHandler(dpid, rep.build())); | ||
| 293 | + } | ||
| 294 | + break; | ||
| 280 | case GROUP: | 295 | case GROUP: |
| 281 | groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply); | 296 | groupStats = publishGroupStats(dpid, (OFGroupStatsReply) reply); |
| 282 | if (groupStats != null) { | 297 | if (groupStats != null) { |
| ... | @@ -395,6 +410,16 @@ public class OpenFlowControllerImpl implements OpenFlowController { | ... | @@ -395,6 +410,16 @@ public class OpenFlowControllerImpl implements OpenFlowController { |
| 395 | return null; | 410 | return null; |
| 396 | } | 411 | } |
| 397 | 412 | ||
| 413 | + private synchronized Collection<OFTableStatsEntry> publishTableStats(Dpid dpid, | ||
| 414 | + OFTableStatsReply reply) { | ||
| 415 | + //TODO: Get rid of synchronized | ||
| 416 | + fullTableStats.putAll(dpid, reply.getEntries()); | ||
| 417 | + if (!reply.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) { | ||
| 418 | + return fullTableStats.removeAll(dpid); | ||
| 419 | + } | ||
| 420 | + return null; | ||
| 421 | + } | ||
| 422 | + | ||
| 398 | private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid, | 423 | private synchronized Collection<OFGroupStatsEntry> publishGroupStats(Dpid dpid, |
| 399 | OFGroupStatsReply reply) { | 424 | OFGroupStatsReply reply) { |
| 400 | //TODO: Get rid of synchronized | 425 | //TODO: Get rid of synchronized | ... | ... |
| ... | @@ -21,6 +21,7 @@ import com.google.common.cache.RemovalCause; | ... | @@ -21,6 +21,7 @@ import com.google.common.cache.RemovalCause; |
| 21 | import com.google.common.cache.RemovalNotification; | 21 | import com.google.common.cache.RemovalNotification; |
| 22 | import com.google.common.collect.Maps; | 22 | import com.google.common.collect.Maps; |
| 23 | import com.google.common.collect.Sets; | 23 | import com.google.common.collect.Sets; |
| 24 | + | ||
| 24 | import org.apache.felix.scr.annotations.Activate; | 25 | import org.apache.felix.scr.annotations.Activate; |
| 25 | import org.apache.felix.scr.annotations.Component; | 26 | import org.apache.felix.scr.annotations.Component; |
| 26 | import org.apache.felix.scr.annotations.Deactivate; | 27 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -32,6 +33,7 @@ import org.onosproject.cfg.ComponentConfigService; | ... | @@ -32,6 +33,7 @@ import org.onosproject.cfg.ComponentConfigService; |
| 32 | import org.onosproject.core.ApplicationId; | 33 | import org.onosproject.core.ApplicationId; |
| 33 | import org.onosproject.net.DeviceId; | 34 | import org.onosproject.net.DeviceId; |
| 34 | import org.onosproject.net.flow.CompletedBatchOperation; | 35 | import org.onosproject.net.flow.CompletedBatchOperation; |
| 36 | +import org.onosproject.net.flow.DefaultTableStatisticsEntry; | ||
| 35 | import org.onosproject.net.flow.FlowEntry; | 37 | import org.onosproject.net.flow.FlowEntry; |
| 36 | import org.onosproject.net.flow.FlowRule; | 38 | import org.onosproject.net.flow.FlowRule; |
| 37 | import org.onosproject.net.flow.FlowRuleBatchEntry; | 39 | import org.onosproject.net.flow.FlowRuleBatchEntry; |
| ... | @@ -40,6 +42,7 @@ import org.onosproject.net.flow.FlowRuleExtPayLoad; | ... | @@ -40,6 +42,7 @@ import org.onosproject.net.flow.FlowRuleExtPayLoad; |
| 40 | import org.onosproject.net.flow.FlowRuleProvider; | 42 | import org.onosproject.net.flow.FlowRuleProvider; |
| 41 | import org.onosproject.net.flow.FlowRuleProviderRegistry; | 43 | import org.onosproject.net.flow.FlowRuleProviderRegistry; |
| 42 | import org.onosproject.net.flow.FlowRuleProviderService; | 44 | import org.onosproject.net.flow.FlowRuleProviderService; |
| 45 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 43 | import org.onosproject.net.provider.AbstractProvider; | 46 | import org.onosproject.net.provider.AbstractProvider; |
| 44 | import org.onosproject.net.provider.ProviderId; | 47 | import org.onosproject.net.provider.ProviderId; |
| 45 | import org.onosproject.net.statistic.DefaultLoad; | 48 | import org.onosproject.net.statistic.DefaultLoad; |
| ... | @@ -58,6 +61,8 @@ import org.projectfloodlight.openflow.protocol.OFErrorType; | ... | @@ -58,6 +61,8 @@ import org.projectfloodlight.openflow.protocol.OFErrorType; |
| 58 | import org.projectfloodlight.openflow.protocol.OFFlowMod; | 61 | import org.projectfloodlight.openflow.protocol.OFFlowMod; |
| 59 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; | 62 | import org.projectfloodlight.openflow.protocol.OFFlowRemoved; |
| 60 | import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; | 63 | import org.projectfloodlight.openflow.protocol.OFFlowStatsReply; |
| 64 | +import org.projectfloodlight.openflow.protocol.OFTableStatsReply; | ||
| 65 | +import org.projectfloodlight.openflow.protocol.OFTableStatsEntry; | ||
| 61 | import org.projectfloodlight.openflow.protocol.OFMessage; | 66 | import org.projectfloodlight.openflow.protocol.OFMessage; |
| 62 | import org.projectfloodlight.openflow.protocol.OFPortStatus; | 67 | import org.projectfloodlight.openflow.protocol.OFPortStatus; |
| 63 | import org.projectfloodlight.openflow.protocol.OFStatsReply; | 68 | import org.projectfloodlight.openflow.protocol.OFStatsReply; |
| ... | @@ -70,6 +75,7 @@ import java.util.Collections; | ... | @@ -70,6 +75,7 @@ import java.util.Collections; |
| 70 | import java.util.Dictionary; | 75 | import java.util.Dictionary; |
| 71 | import java.util.List; | 76 | import java.util.List; |
| 72 | import java.util.Map; | 77 | import java.util.Map; |
| 78 | +import java.util.Objects; | ||
| 73 | import java.util.Optional; | 79 | import java.util.Optional; |
| 74 | import java.util.Set; | 80 | import java.util.Set; |
| 75 | import java.util.Timer; | 81 | import java.util.Timer; |
| ... | @@ -121,6 +127,8 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -121,6 +127,8 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 121 | 127 | ||
| 122 | // NewAdaptiveFlowStatsCollector Set | 128 | // NewAdaptiveFlowStatsCollector Set |
| 123 | private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap(); | 129 | private final Map<Dpid, NewAdaptiveFlowStatsCollector> afsCollectors = Maps.newHashMap(); |
| 130 | + private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap(); | ||
| 131 | + private final Map<Dpid, TableStatisticsCollector> tableStatsCollectors = Maps.newHashMap(); | ||
| 124 | 132 | ||
| 125 | /** | 133 | /** |
| 126 | * Creates an OpenFlow host provider. | 134 | * Creates an OpenFlow host provider. |
| ... | @@ -214,6 +222,9 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -214,6 +222,9 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 214 | fsc.start(); | 222 | fsc.start(); |
| 215 | simpleCollectors.put(new Dpid(sw.getId()), fsc); | 223 | simpleCollectors.put(new Dpid(sw.getId()), fsc); |
| 216 | } | 224 | } |
| 225 | + TableStatisticsCollector tsc = new TableStatisticsCollector(timer, sw, flowPollFrequency); | ||
| 226 | + tsc.start(); | ||
| 227 | + tableStatsCollectors.put(new Dpid(sw.getId()), tsc); | ||
| 217 | } | 228 | } |
| 218 | 229 | ||
| 219 | private void stopCollectors() { | 230 | private void stopCollectors() { |
| ... | @@ -225,17 +236,19 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -225,17 +236,19 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 225 | simpleCollectors.values().forEach(FlowStatsCollector::stop); | 236 | simpleCollectors.values().forEach(FlowStatsCollector::stop); |
| 226 | simpleCollectors.clear(); | 237 | simpleCollectors.clear(); |
| 227 | } | 238 | } |
| 239 | + tableStatsCollectors.values().forEach(TableStatisticsCollector::stop); | ||
| 240 | + tableStatsCollectors.clear(); | ||
| 228 | } | 241 | } |
| 229 | 242 | ||
| 230 | private void adjustRate() { | 243 | private void adjustRate() { |
| 231 | DefaultLoad.setPollInterval(flowPollFrequency); | 244 | DefaultLoad.setPollInterval(flowPollFrequency); |
| 232 | - | ||
| 233 | if (adaptiveFlowSampling) { | 245 | if (adaptiveFlowSampling) { |
| 234 | // NewAdaptiveFlowStatsCollector calAndPollInterval | 246 | // NewAdaptiveFlowStatsCollector calAndPollInterval |
| 235 | afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency)); | 247 | afsCollectors.values().forEach(fsc -> fsc.adjustCalAndPollInterval(flowPollFrequency)); |
| 236 | } else { | 248 | } else { |
| 237 | simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency)); | 249 | simpleCollectors.values().forEach(fsc -> fsc.adjustPollInterval(flowPollFrequency)); |
| 238 | } | 250 | } |
| 251 | + tableStatsCollectors.values().forEach(tsc -> tsc.adjustPollInterval(flowPollFrequency)); | ||
| 239 | } | 252 | } |
| 240 | 253 | ||
| 241 | @Override | 254 | @Override |
| ... | @@ -384,6 +397,10 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -384,6 +397,10 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 384 | collector.stop(); | 397 | collector.stop(); |
| 385 | } | 398 | } |
| 386 | } | 399 | } |
| 400 | + TableStatisticsCollector tsc = tableStatsCollectors.remove(dpid); | ||
| 401 | + if (tsc != null) { | ||
| 402 | + tsc.stop(); | ||
| 403 | + } | ||
| 387 | } | 404 | } |
| 388 | 405 | ||
| 389 | @Override | 406 | @Override |
| ... | @@ -413,6 +430,8 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -413,6 +430,8 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 413 | case STATS_REPLY: | 430 | case STATS_REPLY: |
| 414 | if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) { | 431 | if (((OFStatsReply) msg).getStatsType() == OFStatsType.FLOW) { |
| 415 | pushFlowMetrics(dpid, (OFFlowStatsReply) msg); | 432 | pushFlowMetrics(dpid, (OFFlowStatsReply) msg); |
| 433 | + } else if (((OFStatsReply) msg).getStatsType() == OFStatsType.TABLE) { | ||
| 434 | + pushTableStatistics(dpid, (OFTableStatsReply) msg); | ||
| 416 | } | 435 | } |
| 417 | break; | 436 | break; |
| 418 | case BARRIER_REPLY: | 437 | case BARRIER_REPLY: |
| ... | @@ -473,7 +492,6 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -473,7 +492,6 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 473 | private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) { | 492 | private void pushFlowMetrics(Dpid dpid, OFFlowStatsReply replies) { |
| 474 | 493 | ||
| 475 | DeviceId did = DeviceId.deviceId(Dpid.uri(dpid)); | 494 | DeviceId did = DeviceId.deviceId(Dpid.uri(dpid)); |
| 476 | - OpenFlowSwitch sw = controller.getSwitch(dpid); | ||
| 477 | 495 | ||
| 478 | List<FlowEntry> flowEntries = replies.getEntries().stream() | 496 | List<FlowEntry> flowEntries = replies.getEntries().stream() |
| 479 | .map(entry -> new FlowEntryBuilder(dpid, entry).build()) | 497 | .map(entry -> new FlowEntryBuilder(dpid, entry).build()) |
| ... | @@ -512,6 +530,31 @@ public class OpenFlowRuleProvider extends AbstractProvider | ... | @@ -512,6 +530,31 @@ public class OpenFlowRuleProvider extends AbstractProvider |
| 512 | providerService.pushFlowMetrics(did, flowEntries); | 530 | providerService.pushFlowMetrics(did, flowEntries); |
| 513 | } | 531 | } |
| 514 | } | 532 | } |
| 533 | + | ||
| 534 | + private void pushTableStatistics(Dpid dpid, OFTableStatsReply replies) { | ||
| 535 | + | ||
| 536 | + DeviceId did = DeviceId.deviceId(Dpid.uri(dpid)); | ||
| 537 | + List<TableStatisticsEntry> tableStatsEntries = replies.getEntries().stream() | ||
| 538 | + .map(entry -> buildTableStatistics(did, entry)) | ||
| 539 | + .filter(Objects::nonNull) | ||
| 540 | + .collect(Collectors.toList()); | ||
| 541 | + providerService.pushTableStatistics(did, tableStatsEntries); | ||
| 542 | + } | ||
| 543 | + | ||
| 544 | + private TableStatisticsEntry buildTableStatistics(DeviceId deviceId, | ||
| 545 | + OFTableStatsEntry ofEntry) { | ||
| 546 | + TableStatisticsEntry entry = null; | ||
| 547 | + if (ofEntry != null) { | ||
| 548 | + entry = new DefaultTableStatisticsEntry(deviceId, | ||
| 549 | + ofEntry.getTableId().getValue(), | ||
| 550 | + ofEntry.getActiveCount(), | ||
| 551 | + ofEntry.getLookupCount().getValue(), | ||
| 552 | + ofEntry.getMatchedCount().getValue()); | ||
| 553 | + } | ||
| 554 | + | ||
| 555 | + return entry; | ||
| 556 | + | ||
| 557 | + } | ||
| 515 | } | 558 | } |
| 516 | 559 | ||
| 517 | /** | 560 | /** | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2015 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.onosproject.provider.of.flow.impl; | ||
| 17 | + | ||
| 18 | +import org.onlab.util.SharedExecutors; | ||
| 19 | +import org.onosproject.openflow.controller.OpenFlowSwitch; | ||
| 20 | +import org.onosproject.openflow.controller.RoleState; | ||
| 21 | +import org.projectfloodlight.openflow.protocol.OFTableStatsRequest; | ||
| 22 | +import org.slf4j.Logger; | ||
| 23 | + | ||
| 24 | +import java.util.Timer; | ||
| 25 | +import java.util.TimerTask; | ||
| 26 | + | ||
| 27 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * Collects Table statistics for the specified switch. | ||
| 31 | + */ | ||
| 32 | +class TableStatisticsCollector { | ||
| 33 | + | ||
| 34 | + private final Logger log = getLogger(getClass()); | ||
| 35 | + | ||
| 36 | + public static final int SECONDS = 1000; | ||
| 37 | + | ||
| 38 | + private final OpenFlowSwitch sw; | ||
| 39 | + private Timer timer; | ||
| 40 | + private TimerTask task; | ||
| 41 | + | ||
| 42 | + private int pollInterval; | ||
| 43 | + | ||
| 44 | + /** | ||
| 45 | + * Creates a new table statistics collector for the given switch and poll frequency. | ||
| 46 | + * | ||
| 47 | + * @param timer timer to use for scheduling | ||
| 48 | + * @param sw switch to pull | ||
| 49 | + * @param pollInterval poll frequency in seconds | ||
| 50 | + */ | ||
| 51 | + TableStatisticsCollector(Timer timer, OpenFlowSwitch sw, int pollInterval) { | ||
| 52 | + this.timer = timer; | ||
| 53 | + this.sw = sw; | ||
| 54 | + this.pollInterval = pollInterval; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * Adjusts poll frequency. | ||
| 59 | + * | ||
| 60 | + * @param pollInterval poll frequency in seconds | ||
| 61 | + */ | ||
| 62 | + synchronized void adjustPollInterval(int pollInterval) { | ||
| 63 | + this.pollInterval = pollInterval; | ||
| 64 | + task.cancel(); | ||
| 65 | + task = new InternalTimerTask(); | ||
| 66 | + timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + private class InternalTimerTask extends TimerTask { | ||
| 70 | + @Override | ||
| 71 | + public void run() { | ||
| 72 | + if (sw.getRole() == RoleState.MASTER) { | ||
| 73 | + log.trace("Collecting stats for {}", sw.getStringId()); | ||
| 74 | + OFTableStatsRequest request = sw.factory().buildTableStatsRequest() | ||
| 75 | + .build(); | ||
| 76 | + sw.sendMsg(request); | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + public synchronized void start() { | ||
| 82 | + // Initially start polling quickly. Then drop down to configured value | ||
| 83 | + log.debug("Starting Table Stats collection thread for {}", sw.getStringId()); | ||
| 84 | + task = new InternalTimerTask(); | ||
| 85 | + SharedExecutors.getTimer().scheduleAtFixedRate(task, 1 * SECONDS, | ||
| 86 | + pollInterval * SECONDS); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + public synchronized void stop() { | ||
| 90 | + log.debug("Stopping Table Stats collection thread for {}", sw.getStringId()); | ||
| 91 | + task.cancel(); | ||
| 92 | + task = null; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | +} |
| ... | @@ -21,6 +21,7 @@ import java.util.stream.StreamSupport; | ... | @@ -21,6 +21,7 @@ import java.util.stream.StreamSupport; |
| 21 | 21 | ||
| 22 | import javax.ws.rs.GET; | 22 | import javax.ws.rs.GET; |
| 23 | import javax.ws.rs.Path; | 23 | import javax.ws.rs.Path; |
| 24 | +import javax.ws.rs.PathParam; | ||
| 24 | import javax.ws.rs.Produces; | 25 | import javax.ws.rs.Produces; |
| 25 | import javax.ws.rs.QueryParam; | 26 | import javax.ws.rs.QueryParam; |
| 26 | import javax.ws.rs.core.Context; | 27 | import javax.ws.rs.core.Context; |
| ... | @@ -31,7 +32,12 @@ import javax.ws.rs.core.UriInfo; | ... | @@ -31,7 +32,12 @@ import javax.ws.rs.core.UriInfo; |
| 31 | 32 | ||
| 32 | import org.onosproject.codec.JsonCodec; | 33 | import org.onosproject.codec.JsonCodec; |
| 33 | import org.onosproject.net.ConnectPoint; | 34 | import org.onosproject.net.ConnectPoint; |
| 35 | +import org.onosproject.net.Device; | ||
| 36 | +import org.onosproject.net.DeviceId; | ||
| 34 | import org.onosproject.net.Link; | 37 | import org.onosproject.net.Link; |
| 38 | +import org.onosproject.net.device.DeviceService; | ||
| 39 | +import org.onosproject.net.flow.FlowRuleService; | ||
| 40 | +import org.onosproject.net.flow.TableStatisticsEntry; | ||
| 35 | import org.onosproject.net.link.LinkService; | 41 | import org.onosproject.net.link.LinkService; |
| 36 | import org.onosproject.net.statistic.Load; | 42 | import org.onosproject.net.statistic.Load; |
| 37 | import org.onosproject.net.statistic.StatisticService; | 43 | import org.onosproject.net.statistic.StatisticService; |
| ... | @@ -92,4 +98,59 @@ public class StatisticsWebResource extends AbstractWebResource { | ... | @@ -92,4 +98,59 @@ public class StatisticsWebResource extends AbstractWebResource { |
| 92 | result.set("loads", loads); | 98 | result.set("loads", loads); |
| 93 | return ok(result).build(); | 99 | return ok(result).build(); |
| 94 | } | 100 | } |
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * Get table statistics for all tables of all devices. | ||
| 104 | + * | ||
| 105 | + * @return JSON encoded array of table statistics | ||
| 106 | + */ | ||
| 107 | + @GET | ||
| 108 | + @Path("flows/tables") | ||
| 109 | + @Produces(MediaType.APPLICATION_JSON) | ||
| 110 | + public Response getTableStatistics() { | ||
| 111 | + final FlowRuleService service = get(FlowRuleService.class); | ||
| 112 | + final Iterable<Device> devices = get(DeviceService.class).getDevices(); | ||
| 113 | + final ObjectNode root = mapper().createObjectNode(); | ||
| 114 | + final ArrayNode rootArrayNode = root.putArray("device-table-statistics"); | ||
| 115 | + for (final Device device : devices) { | ||
| 116 | + final ObjectNode deviceStatsNode = mapper().createObjectNode(); | ||
| 117 | + deviceStatsNode.put("device", device.id().toString()); | ||
| 118 | + final ArrayNode statisticsNode = deviceStatsNode.putArray("table-statistics"); | ||
| 119 | + final Iterable<TableStatisticsEntry> tableStatsEntries = service.getFlowTableStatistics(device.id()); | ||
| 120 | + if (tableStatsEntries != null) { | ||
| 121 | + for (final TableStatisticsEntry entry : tableStatsEntries) { | ||
| 122 | + statisticsNode.add(codec(TableStatisticsEntry.class).encode(entry, this)); | ||
| 123 | + } | ||
| 124 | + } | ||
| 125 | + rootArrayNode.add(deviceStatsNode); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + return ok(root).build(); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * Get table statistics for all tables of a specified device. | ||
| 133 | + * | ||
| 134 | + * @param deviceId device ID | ||
| 135 | + * @return JSON encoded array of table statistics | ||
| 136 | + */ | ||
| 137 | + @GET | ||
| 138 | + @Path("flows/tables/{deviceId}") | ||
| 139 | + @Produces(MediaType.APPLICATION_JSON) | ||
| 140 | + public Response getTableStatisticsByDeviceId(@PathParam("deviceId") String deviceId) { | ||
| 141 | + final FlowRuleService service = get(FlowRuleService.class); | ||
| 142 | + final Iterable<TableStatisticsEntry> tableStatisticsEntries = | ||
| 143 | + service.getFlowTableStatistics(DeviceId.deviceId(deviceId)); | ||
| 144 | + final ObjectNode root = mapper().createObjectNode(); | ||
| 145 | + final ArrayNode rootArrayNode = root.putArray("table-statistics"); | ||
| 146 | + | ||
| 147 | + final ObjectNode deviceStatsNode = mapper().createObjectNode(); | ||
| 148 | + deviceStatsNode.put("device", deviceId); | ||
| 149 | + final ArrayNode statisticsNode = deviceStatsNode.putArray("table-statistics"); | ||
| 150 | + for (final TableStatisticsEntry entry : tableStatisticsEntries) { | ||
| 151 | + statisticsNode.add(codec(TableStatisticsEntry.class).encode(entry, this)); | ||
| 152 | + } | ||
| 153 | + rootArrayNode.add(deviceStatsNode); | ||
| 154 | + return ok(root).build(); | ||
| 155 | + } | ||
| 95 | } | 156 | } | ... | ... |
-
Please register or login to post a comment