ssyoon90
Committed by Gerrit Code Review

[Emu] openTAM: FlowStatisticManager, DistributedFlowStatisticStore, get-flow-sta…

…ts CLI Implementation and NewAdaptiveFlowStatsCollector update and typo

 - GetFlowStatistics.java
   .Fixed function name typo: immediateLoad()
 - SummaryFlowEntryWithLoad.java
   .Added javadoc
 - TypedFlowEntryWithLoad.java
   .Added javadoc,
   .and replace checknotnull and throw NullPointerException in typedPollInterval() at line 104

Change-Id: I23d2eaf234d0affeb5f927275148d9165c66c774
...@@ -25,6 +25,8 @@ import org.onosproject.net.ElementId; ...@@ -25,6 +25,8 @@ import org.onosproject.net.ElementId;
25 import org.onosproject.net.Port; 25 import org.onosproject.net.Port;
26 import org.onosproject.net.flow.FlowRule; 26 import org.onosproject.net.flow.FlowRule;
27 import org.onosproject.net.group.Group; 27 import org.onosproject.net.group.Group;
28 +
29 +import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
28 import org.onosproject.net.topology.TopologyCluster; 30 import org.onosproject.net.topology.TopologyCluster;
29 31
30 import java.util.Comparator; 32 import java.util.Comparator;
...@@ -115,4 +117,12 @@ public final class Comparators { ...@@ -115,4 +117,12 @@ public final class Comparators {
115 public static final Comparator<Interface> INTERFACES_COMPARATOR = (intf1, intf2) -> 117 public static final Comparator<Interface> INTERFACES_COMPARATOR = (intf1, intf2) ->
116 CONNECT_POINT_COMPARATOR.compare(intf1.connectPoint(), intf2.connectPoint()); 118 CONNECT_POINT_COMPARATOR.compare(intf1.connectPoint(), intf2.connectPoint());
117 119
120 + public static final Comparator<TypedFlowEntryWithLoad> TYPEFLOWENTRY_WITHLOAD_COMPARATOR =
121 + new Comparator<TypedFlowEntryWithLoad>() {
122 + @Override
123 + public int compare(TypedFlowEntryWithLoad fe1, TypedFlowEntryWithLoad fe2) {
124 + long delta = fe1.load().rate() - fe2.load().rate();
125 + return delta == 0 ? 0 : (delta > 0 ? -1 : +1);
126 + }
127 + };
118 } 128 }
......
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 +
17 +package org.onosproject.cli.net;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.apache.karaf.shell.commands.Option;
22 +import org.onosproject.cli.AbstractShellCommand;
23 +import org.onosproject.net.ConnectPoint;
24 +import org.onosproject.net.Device;
25 +import org.onosproject.net.DeviceId;
26 +import org.onosproject.net.Port;
27 +import org.onosproject.net.PortNumber;
28 +import org.onosproject.net.device.DeviceService;
29 +import org.onosproject.net.flow.TypedStoredFlowEntry;
30 +import org.onosproject.net.flow.instructions.Instruction;
31 +import org.onosproject.net.statistic.FlowStatisticService;
32 +import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
33 +import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
34 +
35 +import java.util.List;
36 +import java.util.Map;
37 +
38 +import static org.onosproject.net.DeviceId.deviceId;
39 +import static org.onosproject.net.PortNumber.portNumber;
40 +
41 +/**
42 + * Fetches flow statistics with a flow type and instruction type.
43 + */
44 +@Command(scope = "onos", name = "get-flow-stats",
45 + description = "Fetches flow stats for a connection point with given flow type and instruction type")
46 +public class GetFlowStatistics extends AbstractShellCommand {
47 + @Argument(index = 0, name = "devicePort",
48 + description = "Device[/Port] connectPoint Description",
49 + required = true, multiValued = false)
50 + String devicePort = null;
51 +
52 + @Option(name = "-s", aliases = "--summary",
53 + description = "Show flow stats summary",
54 + required = false, multiValued = false)
55 + boolean showSummary = true; // default summary
56 +
57 + @Option(name = "-a", aliases = "--all",
58 + description = "Show flow stats all",
59 + required = false, multiValued = false)
60 + boolean showAll = false;
61 +
62 + @Option(name = "-t", aliases = "--topn",
63 + description = "Show flow stats topn",
64 + required = false, multiValued = false)
65 + String showTopn = null;
66 +
67 + @Option(name = "-f", aliases = "--flowType",
68 + description = "Flow live type, It includes IMMEDIATE, SHORT, MID, LONG, UNKNOWN"
69 + + ", and is valid with -a or -t option only",
70 + required = false, multiValued = false)
71 + String flowLiveType = null;
72 +
73 + @Option(name = "-i", aliases = "--instructionType",
74 + description = "Flow instruction type, It includes DROP, OUTPUT, GROUP, L0MODIFICATION, L2MODIFICATION,"
75 + + " TABLE, L3MODIFICATION, METADATA"
76 + + ", and is valid with -a or -t option only",
77 + required = false, multiValued = false)
78 + String instructionType = null;
79 +
80 + @Override
81 + protected void execute() {
82 + DeviceService deviceService = get(DeviceService.class);
83 + FlowStatisticService flowStatsService = get(FlowStatisticService.class);
84 +
85 + String deviceURI = getDeviceId(devicePort);
86 + String portURI = getPortNumber(devicePort);
87 +
88 + DeviceId ingressDeviceId = deviceId(deviceURI);
89 + PortNumber ingressPortNumber;
90 + if (portURI.length() == 0) {
91 + ingressPortNumber = null;
92 + } else {
93 + ingressPortNumber = portNumber(portURI);
94 + }
95 +
96 + Device device = deviceService.getDevice(ingressDeviceId);
97 + if (device == null) {
98 + error("No such device %s", ingressDeviceId.uri());
99 + return;
100 + }
101 +
102 + if (ingressPortNumber != null) {
103 + Port port = deviceService.getPort(ingressDeviceId, ingressPortNumber);
104 + if (port == null) {
105 + error("No such port %s on device %s", portURI, ingressDeviceId.uri());
106 + return;
107 + }
108 + }
109 +
110 + if (flowLiveType != null) {
111 + flowLiveType = flowLiveType.toUpperCase();
112 + }
113 + if (instructionType != null) {
114 + instructionType = instructionType.toUpperCase();
115 + }
116 +
117 + // convert String to FlowLiveType and check validity
118 + TypedStoredFlowEntry.FlowLiveType inLiveType;
119 + if (flowLiveType == null) {
120 + inLiveType = null;
121 + } else {
122 + inLiveType = getFlowLiveType(flowLiveType);
123 + if (inLiveType == null) {
124 + error("Invalid flow live type [%s] error", flowLiveType);
125 + return;
126 + }
127 + }
128 + // convert String to InstructionType and check validity
129 + Instruction.Type inInstructionType;
130 + if (instructionType == null) {
131 + inInstructionType = null;
132 + } else {
133 + inInstructionType = getInstructionType(instructionType);
134 + if (inInstructionType == null) {
135 + error("Invalid instruction type [%s] error", instructionType);
136 + return;
137 + }
138 + }
139 +
140 + if (showTopn != null) {
141 + int topn = Integer.parseInt(showTopn);
142 +
143 + if (topn <= 0) {
144 + topn = 100; //default value
145 + } else if (topn > 1000) {
146 + topn = 1000; //max value
147 + }
148 +
149 + // print show topn head line with type
150 + print("deviceId=%s, show TOPN=%s flows, live type=%s, instruction type=%s",
151 + deviceURI,
152 + Integer.toString(topn),
153 + flowLiveType == null ? "ALL" : flowLiveType,
154 + instructionType == null ? "ALL" : instructionType);
155 + if (ingressPortNumber == null) {
156 + Map<ConnectPoint, List<TypedFlowEntryWithLoad>> typedFlowLoadMap =
157 + flowStatsService.loadTopnByType(device, inLiveType, inInstructionType, topn);
158 + // print all ports topn flows load for a given device
159 + for (ConnectPoint cp : typedFlowLoadMap.keySet()) {
160 + printPortFlowsLoad(cp, typedFlowLoadMap.get(cp));
161 + }
162 + } else {
163 + List<TypedFlowEntryWithLoad> typedFlowLoad =
164 + flowStatsService.loadTopnByType(device, ingressPortNumber, inLiveType, inInstructionType, topn);
165 + // print device/port topn flows load
166 + ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber);
167 + printPortFlowsLoad(cp, typedFlowLoad);
168 + }
169 + } else if (showAll) { // is true?
170 + // print show all head line with type
171 + print("deviceId=%s, show ALL flows, live type=%s, instruction type=%s",
172 + deviceURI,
173 + flowLiveType == null ? "ALL" : flowLiveType,
174 + instructionType == null ? "ALL" : instructionType);
175 + if (ingressPortNumber == null) {
176 + Map<ConnectPoint, List<TypedFlowEntryWithLoad>> typedFlowLoadMap =
177 + flowStatsService.loadAllByType(device, inLiveType, inInstructionType);
178 + // print all ports all flows load for a given device
179 + for (ConnectPoint cp : typedFlowLoadMap.keySet()) {
180 + printPortFlowsLoad(cp, typedFlowLoadMap.get(cp));
181 + }
182 + } else {
183 + List<TypedFlowEntryWithLoad> typedFlowLoad =
184 + flowStatsService.loadAllByType(device, ingressPortNumber, inLiveType, inInstructionType);
185 + // print device/port all flows load
186 + ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber);
187 + printPortFlowsLoad(cp, typedFlowLoad);
188 + }
189 + } else { // if (showSummary == true) //always is true
190 + // print show summary head line
191 + print("deviceId=%s, show SUMMARY flows", deviceURI);
192 + if (ingressPortNumber == null) {
193 + Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryFlowLoadMap =
194 + flowStatsService.loadSummary(device);
195 + // print all ports flow load summary for a given device
196 + for (ConnectPoint cp : summaryFlowLoadMap.keySet()) {
197 + printPortSummaryLoad(cp, summaryFlowLoadMap.get(cp));
198 + }
199 + } else {
200 + SummaryFlowEntryWithLoad summaryFlowLoad =
201 + flowStatsService.loadSummary(device, ingressPortNumber);
202 + // print device/port flow load summary
203 + ConnectPoint cp = new ConnectPoint(ingressDeviceId, ingressPortNumber);
204 + printPortSummaryLoad(cp, summaryFlowLoad);
205 + }
206 + }
207 + }
208 +
209 + /**
210 + * Extracts the port number portion of the ConnectPoint.
211 + *
212 + * @param deviceString string representing the device/port
213 + * @return port number as a string, empty string if the port is not found
214 + */
215 + private String getPortNumber(String deviceString) {
216 + if (deviceString == null) {
217 + return "";
218 + }
219 +
220 + int slash = deviceString.indexOf('/');
221 + if (slash <= 0) {
222 + return ""; // return when no port number
223 + }
224 + return deviceString.substring(slash + 1, deviceString.length());
225 + }
226 +
227 + /**
228 + * Extracts the device ID portion of the ConnectPoint.
229 + *
230 + * @param deviceString string representing the device/port
231 + * @return device ID string
232 + */
233 + private String getDeviceId(String deviceString) {
234 + if (deviceString == null) {
235 + return "";
236 + }
237 +
238 + int slash = deviceString.indexOf('/');
239 + if (slash <= 0) {
240 + return deviceString; // return only included device ID
241 + }
242 + return deviceString.substring(0, slash);
243 + }
244 +
245 + /**
246 + * converts string of flow live type to FloeLiveType enum.
247 + *
248 + * @param liveType string representing the flow live type
249 + * @return TypedStoredFlowEntry.FlowLiveType
250 + */
251 + private TypedStoredFlowEntry.FlowLiveType getFlowLiveType(String liveType) {
252 + String liveTypeUC = liveType.toUpperCase();
253 +
254 + if (liveTypeUC.equals("IMMEDIATE")) {
255 + return TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW;
256 + } else if (liveTypeUC.equals("SHORT")) {
257 + return TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW;
258 + } else if (liveTypeUC.equals("MID")) {
259 + return TypedStoredFlowEntry.FlowLiveType.MID_FLOW;
260 + } else if (liveTypeUC.equals("LONG")) {
261 + return TypedStoredFlowEntry.FlowLiveType.LONG_FLOW;
262 + } else if (liveTypeUC.equals("UNKNOWN")) {
263 + return TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW;
264 + } else {
265 + return null; // flow live type error
266 + }
267 + }
268 +
269 + /**
270 + * converts string of instruction type to Instruction type enum.
271 + *
272 + * @param instType string representing the instruction type
273 + * @return Instruction.Type
274 + */
275 + private Instruction.Type getInstructionType(String instType) {
276 + String instTypeUC = instType.toUpperCase();
277 +
278 + if (instTypeUC.equals("DROP")) {
279 + return Instruction.Type.DROP;
280 + } else if (instTypeUC.equals("OUTPUT")) {
281 + return Instruction.Type.OUTPUT;
282 + } else if (instTypeUC.equals("GROUP")) {
283 + return Instruction.Type.GROUP;
284 + } else if (instTypeUC.equals("L0MODIFICATION")) {
285 + return Instruction.Type.L0MODIFICATION;
286 + } else if (instTypeUC.equals("L2MODIFICATION")) {
287 + return Instruction.Type.L2MODIFICATION;
288 + } else if (instTypeUC.equals("TABLE")) {
289 + return Instruction.Type.TABLE;
290 + } else if (instTypeUC.equals("L3MODIFICATION")) {
291 + return Instruction.Type.L3MODIFICATION;
292 + } else if (instTypeUC.equals("METADATA")) {
293 + return Instruction.Type.METADATA;
294 + } else {
295 + return null; // instruction type error
296 + }
297 + }
298 +
299 + private void printPortFlowsLoad(ConnectPoint cp, List<TypedFlowEntryWithLoad> typedFlowLoad) {
300 + print(" deviceId/Port=%s/%s, %s flows", cp.elementId(), cp.port(), typedFlowLoad.size());
301 + for (TypedFlowEntryWithLoad tfel: typedFlowLoad) {
302 + TypedStoredFlowEntry tfe = tfel.typedStoredFlowEntry();
303 + print(" flowId=%s, state=%s, liveType=%s, life=%s -> %s",
304 + Long.toHexString(tfe.id().value()),
305 + tfe.state(),
306 + tfe.flowLiveType(),
307 + tfe.life(),
308 + tfel.load().isValid() ? tfel.load() : "Load{rate=0, NOT VALID}");
309 + }
310 + }
311 +
312 + private void printPortSummaryLoad(ConnectPoint cp, SummaryFlowEntryWithLoad summaryFlowLoad) {
313 + print(" deviceId/Port=%s/%s, Total=%s, Immediate=%s, Short=%s, Mid=%s, Long=%s, Unknown=%s",
314 + cp.elementId(),
315 + cp.port(),
316 + summaryFlowLoad.totalLoad().isValid() ? summaryFlowLoad.totalLoad() : "Load{rate=0, NOT VALID}",
317 + summaryFlowLoad.immediateLoad().isValid() ? summaryFlowLoad.immediateLoad() : "Load{rate=0, NOT VALID}",
318 + summaryFlowLoad.shortLoad().isValid() ? summaryFlowLoad.shortLoad() : "Load{rate=0, NOT VALID}",
319 + summaryFlowLoad.midLoad().isValid() ? summaryFlowLoad.midLoad() : "Load{rate=0, NOT VALID}",
320 + summaryFlowLoad.longLoad().isValid() ? summaryFlowLoad.longLoad() : "Load{rate=0, NOT VALID}",
321 + summaryFlowLoad.unknownLoad().isValid() ? summaryFlowLoad.unknownLoad() : "Load{rate=0, NOT VALID}");
322 + }
323 +}
...@@ -222,6 +222,12 @@ ...@@ -222,6 +222,12 @@
222 </completers> 222 </completers>
223 </command> 223 </command>
224 <command> 224 <command>
225 + <action class="org.onosproject.cli.net.GetFlowStatistics"/>
226 + <completers>
227 + <ref component-id="deviceIdCompleter"/>
228 + </completers>
229 + </command>
230 + <command>
225 <action class="org.onosproject.cli.net.AddMultiPointToSinglePointIntentCommand"/> 231 <action class="org.onosproject.cli.net.AddMultiPointToSinglePointIntentCommand"/>
226 <completers> 232 <completers>
227 <ref component-id="connectPointCompleter"/> 233 <ref component-id="connectPointCompleter"/>
...@@ -333,7 +339,6 @@ ...@@ -333,7 +339,6 @@
333 <command> 339 <command>
334 <action class="org.onosproject.cli.net.InterfacesListCommand"/> 340 <action class="org.onosproject.cli.net.InterfacesListCommand"/>
335 </command> 341 </command>
336 -
337 <command> 342 <command>
338 <action class="org.onosproject.cli.net.GroupsListCommand"/> 343 <action class="org.onosproject.cli.net.GroupsListCommand"/>
339 </command> 344 </command>
......
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 +
17 +package org.onosproject.net.statistic;
18 +
19 +import org.onosproject.net.ConnectPoint;
20 +import org.onosproject.net.Device;
21 +import org.onosproject.net.PortNumber;
22 +import org.onosproject.net.flow.TypedStoredFlowEntry;
23 +import org.onosproject.net.flow.instructions.Instruction;
24 +
25 +import java.util.List;
26 +import java.util.Map;
27 +
28 +/**
29 + * Service for obtaining individual flow statistic information about device and link in the system.
30 + * Basic statistics are obtained from the StatisticService
31 + */
32 +public interface FlowStatisticService {
33 +
34 + /**
35 + * Obtain the summary load list for the device with the given link.
36 + *
37 + * @param device the Device to query.
38 + * @return map of summary flow entry load
39 + */
40 + Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device);
41 +
42 + /**
43 + * Obtain the summary load for the device with the given link or port.
44 + *
45 + * @param device the Device to query.
46 + * @param pNumber the port number to query.
47 + * @return summary flow entry load
48 + */
49 + SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber);
50 +
51 + /**
52 + * Obtain the set of the flow type and load list for the device with the given link.
53 + *
54 + * @param device the Device to query.
55 + * @param liveType the FlowLiveType to filter, null means no filtering .
56 + * @param instType the InstructionType to filter, null means no filtering.
57 + * @return map of flow entry load
58 + */
59 + Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
60 + TypedStoredFlowEntry.FlowLiveType liveType,
61 + Instruction.Type instType);
62 +
63 + /**
64 + * Obtain the flow type and load list for the device with the given link or port.
65 + *
66 + * @param device the Device to query.
67 + * @param pNumber the port number of the Device to query
68 + * @param liveType the FlowLiveType to filter, null means no filtering .
69 + * @param instType the InstructionType to filter, null means no filtering.
70 + * @return list of flow entry load
71 + */
72 + List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
73 + TypedStoredFlowEntry.FlowLiveType liveType,
74 + Instruction.Type instType);
75 +
76 + /**
77 + * Obtain the set of the flow type and load topn list for the device with the given link.
78 + *
79 + * @param device the Device to query.
80 + * @param liveType the FlowLiveType to filter, null means no filtering .
81 + * @param instType the InstructionType to filter, null means no filtering.
82 + * @param topn the top number to filter, null means no filtering.
83 + * @return map of flow entry load
84 + */
85 + Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
86 + TypedStoredFlowEntry.FlowLiveType liveType,
87 + Instruction.Type instType,
88 + int topn);
89 +
90 + /**
91 + * Obtain the flow type and load topn list for the device with the given link or port.
92 + *
93 + * @param device the Device to query.
94 + * @param pNumber the port number of the Device to query
95 + * @param liveType the FlowLiveType to filter, null means no filtering .
96 + * @param instType the InstructionType to filter, null means no filtering.
97 + * @return list of flow entry load
98 + */
99 + List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
100 + TypedStoredFlowEntry.FlowLiveType liveType,
101 + Instruction.Type instType,
102 + int topn);
103 +}
104 +
105 +
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 +
17 +package org.onosproject.net.statistic;
18 +
19 +import org.onosproject.net.ConnectPoint;
20 +import org.onosproject.net.flow.FlowEntry;
21 +import org.onosproject.net.flow.FlowRule;
22 +
23 +import java.util.Set;
24 +
25 +/**
26 + * Flow Store to house the computed statistics.
27 + */
28 +public interface FlowStatisticStore {
29 + /**
30 + * Remove entries associated with this rule.
31 + *
32 + * @param rule {@link org.onosproject.net.flow.FlowRule}
33 + */
34 + void removeFlowStatistic(FlowRule rule);
35 +
36 + /**
37 + * Adds a flow stats observation for a flow rule. The previous flow will be removed.
38 + *
39 + * @param rule a {@link org.onosproject.net.flow.FlowEntry}
40 + */
41 + void addFlowStatistic(FlowEntry rule);
42 +
43 + /**
44 + * Updates a stats observation for a flow rule. The old flow stats will be moved to previous stats.
45 + *
46 + * @param rule a {@link org.onosproject.net.flow.FlowEntry}
47 + */
48 + void updateFlowStatistic(FlowEntry rule);
49 +
50 + /**
51 + * Fetches the current observed flow stats values.
52 + *
53 + * @param connectPoint the port to fetch information for
54 + * @return set of current flow rules
55 + */
56 + Set<FlowEntry> getCurrentFlowStatistic(ConnectPoint connectPoint);
57 +
58 + /**
59 + * Fetches the current observed flow stats values.
60 + *
61 + * @param connectPoint the port to fetch information for
62 + * @return set of current values
63 + */
64 + Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint);
65 +}
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 +
17 +package org.onosproject.net.statistic;
18 +
19 +import org.onosproject.net.ConnectPoint;
20 +
21 +/**
22 + * Summary Load classified by flow live type.
23 + */
24 +public class SummaryFlowEntryWithLoad {
25 + private ConnectPoint cp;
26 + private Load totalLoad;
27 + private Load immediateLoad;
28 + private Load shortLoad;
29 + private Load midLoad;
30 + private Load longLoad;
31 + private Load unknownLoad;
32 +
33 + /**
34 + * Creates a new summary flow entry having load for the given connect point and total load.
35 + *
36 + * @param cp connect point
37 + * @param totalLoad total load
38 + */
39 + public SummaryFlowEntryWithLoad(ConnectPoint cp, Load totalLoad) {
40 + this.cp = cp;
41 + this.totalLoad = totalLoad;
42 + this.immediateLoad = new DefaultLoad();
43 + this.shortLoad = new DefaultLoad();
44 + this.midLoad = new DefaultLoad();
45 + this.longLoad = new DefaultLoad();
46 + this.unknownLoad = new DefaultLoad();
47 + }
48 +
49 + /**
50 + * Creates a new summary flow entry having load for the given connect point
51 + * and total, immediate, short, mid, and long load.
52 + *
53 + * @param cp connect point
54 + * @param totalLoad total load
55 + * @param immediateLoad immediate load
56 + * @param shortLoad short load
57 + * @param midLoad mid load
58 + * @param longLoad long load
59 + */
60 + public SummaryFlowEntryWithLoad(ConnectPoint cp,
61 + Load totalLoad, Load immediateLoad, Load shortLoad, Load midLoad, Load longLoad) {
62 + this.cp = cp;
63 + this.totalLoad = totalLoad;
64 + this.immediateLoad = immediateLoad;
65 + this.shortLoad = shortLoad;
66 + this.midLoad = midLoad;
67 + this.longLoad = longLoad;
68 + this.unknownLoad = new DefaultLoad();
69 + }
70 +
71 + /**
72 + * Creates a new summary flow entry having load for the given connect point
73 + * and total, immediate, short, mid, long, and unknown load.
74 + *
75 + * @param cp connect point
76 + * @param totalLoad total load
77 + * @param immediateLoad immediate load
78 + * @param shortLoad short load
79 + * @param midLoad mid load
80 + * @param longLoad long load
81 + * @param unknownLoad long load
82 + */
83 + public SummaryFlowEntryWithLoad(ConnectPoint cp,
84 + Load totalLoad, Load immediateLoad,
85 + Load shortLoad, Load midLoad, Load longLoad, Load unknownLoad) {
86 + this.cp = cp;
87 + this.totalLoad = totalLoad;
88 + this.immediateLoad = immediateLoad;
89 + this.shortLoad = shortLoad;
90 + this.midLoad = midLoad;
91 + this.longLoad = longLoad;
92 + this.unknownLoad = unknownLoad;
93 + }
94 +
95 + /**
96 + * Returns connect point.
97 + */
98 + public ConnectPoint connectPoint() {
99 + return cp;
100 + }
101 +
102 + /**
103 + * Returns total load of connect point.
104 + */
105 + public Load totalLoad() {
106 + return totalLoad;
107 + }
108 +
109 + /**
110 + * Returns immediate load of connect point.
111 + */
112 + public Load immediateLoad() {
113 + return immediateLoad;
114 + }
115 +
116 + /**
117 + * Returns short load of connect point.
118 + */
119 + public Load shortLoad() {
120 + return shortLoad;
121 + }
122 +
123 + /**
124 + * Returns mid load of connect point.
125 + */
126 + public Load midLoad() {
127 + return midLoad;
128 + }
129 +
130 + /**
131 + * Returns long load of connect point.
132 + */
133 + public Load longLoad() {
134 + return longLoad;
135 + }
136 +
137 + /**
138 + * Returns unknown load of connect point.
139 + */
140 + public Load unknownLoad() {
141 + return unknownLoad;
142 + }
143 +}
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 +
17 +package org.onosproject.net.statistic;
18 +
19 +import org.onosproject.net.ConnectPoint;
20 +import org.onosproject.net.flow.FlowEntry;
21 +import org.onosproject.net.flow.TypedStoredFlowEntry;
22 +import org.onosproject.net.flow.DefaultTypedFlowEntry;
23 +
24 +import static com.google.common.base.Preconditions.checkNotNull;
25 +
26 +/**
27 + * Load of flow entry of flow live type.
28 + */
29 +public class TypedFlowEntryWithLoad {
30 + private ConnectPoint cp;
31 + private TypedStoredFlowEntry tfe;
32 + private Load load;
33 +
34 + //TODO: make this variables class, and share with NewAdaptivceFlowStatsCollector class
35 + private static final int CAL_AND_POLL_INTERVAL = 5; // means SHORT_POLL_INTERVAL
36 + private static final int MID_POLL_INTERVAL = 10;
37 + private static final int LONG_POLL_INTERVAL = 15;
38 +
39 +
40 + public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe, Load load) {
41 + this.cp = cp;
42 + this.tfe = tfe;
43 + this.load = load;
44 + }
45 +
46 + public TypedFlowEntryWithLoad(ConnectPoint cp, TypedStoredFlowEntry tfe) {
47 + this.cp = cp;
48 + this.tfe = tfe;
49 + this.load = new DefaultLoad(tfe.bytes(), 0, typedPollInterval(tfe));
50 + }
51 +
52 + public TypedFlowEntryWithLoad(ConnectPoint cp, FlowEntry fe) {
53 + this.cp = cp;
54 + this.tfe = newTypedStoredFlowEntry(fe);
55 + this.load = new DefaultLoad(fe.bytes(), 0, typedPollInterval(this.tfe));
56 + }
57 +
58 + public ConnectPoint connectPoint() {
59 + return cp;
60 + }
61 + public TypedStoredFlowEntry typedStoredFlowEntry() {
62 + return tfe;
63 + }
64 + public Load load() {
65 + return load;
66 + }
67 + public void setLoad(Load load) {
68 + this.load = load;
69 + }
70 +
71 + /**
72 + * Returns short polling interval.
73 + */
74 + public static int shortPollInterval() {
75 + return CAL_AND_POLL_INTERVAL;
76 + }
77 +
78 + /**
79 + * Returns mid polling interval.
80 + */
81 + public static int midPollInterval() {
82 + return MID_POLL_INTERVAL;
83 + }
84 +
85 + /**
86 + * Returns long polling interval.
87 + */
88 + public static int longPollInterval() {
89 + return LONG_POLL_INTERVAL;
90 + }
91 +
92 + /**
93 + * Returns average polling interval.
94 + */
95 + public static int avgPollInterval() {
96 + return (CAL_AND_POLL_INTERVAL + MID_POLL_INTERVAL + LONG_POLL_INTERVAL) / 3;
97 + }
98 +
99 + /**
100 + * Returns current typed flow entry's polling interval.
101 + *
102 + * @param tfe typed flow entry
103 + */
104 + public static long typedPollInterval(TypedStoredFlowEntry tfe) {
105 + checkNotNull(tfe, "TypedStoredFlowEntry cannot be null");
106 +
107 + switch (tfe.flowLiveType()) {
108 + case LONG_FLOW:
109 + return LONG_POLL_INTERVAL;
110 + case MID_FLOW:
111 + return MID_POLL_INTERVAL;
112 + case SHORT_FLOW:
113 + case IMMEDIATE_FLOW:
114 + default:
115 + return CAL_AND_POLL_INTERVAL;
116 + }
117 + }
118 +
119 + /**
120 + * Creates a new typed flow entry with the given flow entry fe.
121 + *
122 + * @param fe flow entry
123 + */
124 + public static TypedStoredFlowEntry newTypedStoredFlowEntry(FlowEntry fe) {
125 + if (fe == null) {
126 + return null;
127 + }
128 +
129 + long life = fe.life();
130 +
131 + if (life >= LONG_POLL_INTERVAL) {
132 + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.LONG_FLOW);
133 + } else if (life >= MID_POLL_INTERVAL) {
134 + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.MID_FLOW);
135 + } else if (life >= CAL_AND_POLL_INTERVAL) {
136 + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW);
137 + } else if (life >= 0) {
138 + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW);
139 + } else { // life < 0
140 + return new DefaultTypedFlowEntry(fe, TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW);
141 + }
142 + }
143 +}
...@@ -52,6 +52,20 @@ ...@@ -52,6 +52,20 @@
52 52
53 <dependency> 53 <dependency>
54 <groupId>org.onosproject</groupId> 54 <groupId>org.onosproject</groupId>
55 + <version>${project.version}</version>
56 + <artifactId>onos-cli</artifactId>
57 + </dependency>
58 +
59 + <dependency>
60 + <groupId>org.onosproject</groupId>
61 + <artifactId>onos-cli</artifactId>
62 + <version>${project.version}</version>
63 + <classifier>tests</classifier>
64 + <scope>test</scope>
65 + </dependency>
66 +
67 + <dependency>
68 + <groupId>org.onosproject</groupId>
55 <artifactId>onos-core-common</artifactId> 69 <artifactId>onos-core-common</artifactId>
56 <version>${project.version}</version> 70 <version>${project.version}</version>
57 <classifier>tests</classifier> 71 <classifier>tests</classifier>
......
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 +
17 +package org.onosproject.net.statistic.impl;
18 +
19 +import com.google.common.base.MoreObjects;
20 +import com.google.common.base.Predicate;
21 +import com.google.common.collect.ImmutableSet;
22 +import org.apache.felix.scr.annotations.Activate;
23 +import org.apache.felix.scr.annotations.Component;
24 +import org.apache.felix.scr.annotations.Deactivate;
25 +import org.apache.felix.scr.annotations.Reference;
26 +import org.apache.felix.scr.annotations.ReferenceCardinality;
27 +import org.apache.felix.scr.annotations.Service;
28 +import org.onosproject.cli.Comparators;
29 +import org.onosproject.net.ConnectPoint;
30 +import org.onosproject.net.Device;
31 +import org.onosproject.net.Port;
32 +import org.onosproject.net.PortNumber;
33 +import org.onosproject.net.device.DeviceService;
34 +import org.onosproject.net.flow.DefaultTypedFlowEntry;
35 +import org.onosproject.net.flow.FlowEntry;
36 +import org.onosproject.net.flow.FlowRule;
37 +import org.onosproject.net.flow.FlowRuleEvent;
38 +import org.onosproject.net.flow.FlowRuleListener;
39 +import org.onosproject.net.flow.FlowRuleService;
40 +import org.onosproject.net.flow.TypedStoredFlowEntry;
41 +import org.onosproject.net.flow.instructions.Instruction;
42 +import org.onosproject.net.statistic.DefaultLoad;
43 +import org.onosproject.net.statistic.FlowStatisticService;
44 +import org.onosproject.net.statistic.Load;
45 +import org.onosproject.net.statistic.FlowStatisticStore;
46 +import org.onosproject.net.statistic.SummaryFlowEntryWithLoad;
47 +import org.onosproject.net.statistic.TypedFlowEntryWithLoad;
48 +
49 +import org.slf4j.Logger;
50 +
51 +import java.util.ArrayList;
52 +import java.util.HashMap;
53 +import java.util.List;
54 +import java.util.Map;
55 +import java.util.Objects;
56 +import java.util.Set;
57 +import java.util.TreeMap;
58 +import java.util.stream.Collectors;
59 +
60 +import static com.google.common.base.Preconditions.checkNotNull;
61 +import static org.onosproject.security.AppGuard.checkPermission;
62 +import static org.slf4j.LoggerFactory.getLogger;
63 +import static org.onosproject.security.AppPermission.Type.*;
64 +
65 +/**
66 + * Provides an implementation of the Flow Statistic Service.
67 + */
68 +@Component(immediate = true, enabled = true)
69 +@Service
70 +public class FlowStatisticManager implements FlowStatisticService {
71 + private final Logger log = getLogger(getClass());
72 +
73 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 + protected FlowRuleService flowRuleService;
75 +
76 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 + protected FlowStatisticStore flowStatisticStore;
78 +
79 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 + protected DeviceService deviceService;
81 +
82 + private final InternalFlowRuleStatsListener frListener = new InternalFlowRuleStatsListener();
83 +
84 + @Activate
85 + public void activate() {
86 + flowRuleService.addListener(frListener);
87 + log.info("Started");
88 + }
89 +
90 + @Deactivate
91 + public void deactivate() {
92 + flowRuleService.removeListener(frListener);
93 + log.info("Stopped");
94 + }
95 +
96 + @Override
97 + public Map<ConnectPoint, SummaryFlowEntryWithLoad> loadSummary(Device device) {
98 + checkPermission(STATISTIC_READ);
99 +
100 + Map<ConnectPoint, SummaryFlowEntryWithLoad> summaryLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
101 +
102 + if (device == null) {
103 + return summaryLoad;
104 + }
105 +
106 + List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
107 +
108 + for (Port port : ports) {
109 + ConnectPoint cp = new ConnectPoint(device.id(), port.number());
110 + SummaryFlowEntryWithLoad sfe = loadSummaryPortInternal(cp);
111 + summaryLoad.put(cp, sfe);
112 + }
113 +
114 + return summaryLoad;
115 + }
116 +
117 + @Override
118 + public SummaryFlowEntryWithLoad loadSummary(Device device, PortNumber pNumber) {
119 + checkPermission(STATISTIC_READ);
120 +
121 + ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
122 + return loadSummaryPortInternal(cp);
123 + }
124 +
125 + @Override
126 + public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadAllByType(Device device,
127 + TypedStoredFlowEntry.FlowLiveType liveType,
128 + Instruction.Type instType) {
129 + checkPermission(STATISTIC_READ);
130 +
131 + Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
132 +
133 + if (device == null) {
134 + return allLoad;
135 + }
136 +
137 + List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
138 +
139 + for (Port port : ports) {
140 + ConnectPoint cp = new ConnectPoint(device.id(), port.number());
141 + List<TypedFlowEntryWithLoad> tfel = loadAllPortInternal(cp, liveType, instType);
142 + allLoad.put(cp, tfel);
143 + }
144 +
145 + return allLoad;
146 + }
147 +
148 + @Override
149 + public List<TypedFlowEntryWithLoad> loadAllByType(Device device, PortNumber pNumber,
150 + TypedStoredFlowEntry.FlowLiveType liveType,
151 + Instruction.Type instType) {
152 + checkPermission(STATISTIC_READ);
153 +
154 + ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
155 + return loadAllPortInternal(cp, liveType, instType);
156 + }
157 +
158 + @Override
159 + public Map<ConnectPoint, List<TypedFlowEntryWithLoad>> loadTopnByType(Device device,
160 + TypedStoredFlowEntry.FlowLiveType liveType,
161 + Instruction.Type instType,
162 + int topn) {
163 + checkPermission(STATISTIC_READ);
164 +
165 + Map<ConnectPoint, List<TypedFlowEntryWithLoad>> allLoad = new TreeMap<>(Comparators.CONNECT_POINT_COMPARATOR);
166 +
167 + if (device == null) {
168 + return allLoad;
169 + }
170 +
171 + List<Port> ports = new ArrayList<>(deviceService.getPorts(device.id()));
172 +
173 + for (Port port : ports) {
174 + ConnectPoint cp = new ConnectPoint(device.id(), port.number());
175 + List<TypedFlowEntryWithLoad> tfel = loadTopnPortInternal(cp, liveType, instType, topn);
176 + allLoad.put(cp, tfel);
177 + }
178 +
179 + return allLoad;
180 + }
181 +
182 + @Override
183 + public List<TypedFlowEntryWithLoad> loadTopnByType(Device device, PortNumber pNumber,
184 + TypedStoredFlowEntry.FlowLiveType liveType,
185 + Instruction.Type instType,
186 + int topn) {
187 + checkPermission(STATISTIC_READ);
188 +
189 + ConnectPoint cp = new ConnectPoint(device.id(), pNumber);
190 + return loadTopnPortInternal(cp, liveType, instType, topn);
191 + }
192 +
193 + private SummaryFlowEntryWithLoad loadSummaryPortInternal(ConnectPoint cp) {
194 + checkPermission(STATISTIC_READ);
195 +
196 + Set<FlowEntry> currentStats;
197 + Set<FlowEntry> previousStats;
198 +
199 + TypedStatistics typedStatistics;
200 + synchronized (flowStatisticStore) {
201 + currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);
202 + if (currentStats == null) {
203 + return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
204 + }
205 + previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);
206 + if (previousStats == null) {
207 + return new SummaryFlowEntryWithLoad(cp, new DefaultLoad());
208 + }
209 + // copy to local flow entry
210 + typedStatistics = new TypedStatistics(currentStats, previousStats);
211 +
212 + // Check for validity of this stats data
213 + checkLoadValidity(currentStats, previousStats);
214 + }
215 +
216 + // current and previous set is not empty!
217 + Set<FlowEntry> currentSet = typedStatistics.current();
218 + Set<FlowEntry> previousSet = typedStatistics.previous();
219 + Load totalLoad = new DefaultLoad(aggregateBytesSet(currentSet), aggregateBytesSet(previousSet),
220 + TypedFlowEntryWithLoad.avgPollInterval());
221 +
222 + Map<FlowRule, TypedStoredFlowEntry> currentMap;
223 + Map<FlowRule, TypedStoredFlowEntry> previousMap;
224 +
225 + currentMap = typedStatistics.currentImmediate();
226 + previousMap = typedStatistics.previousImmediate();
227 + Load immediateLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
228 + TypedFlowEntryWithLoad.shortPollInterval());
229 +
230 + currentMap = typedStatistics.currentShort();
231 + previousMap = typedStatistics.previousShort();
232 + Load shortLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
233 + TypedFlowEntryWithLoad.shortPollInterval());
234 +
235 + currentMap = typedStatistics.currentMid();
236 + previousMap = typedStatistics.previousMid();
237 + Load midLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
238 + TypedFlowEntryWithLoad.midPollInterval());
239 +
240 + currentMap = typedStatistics.currentLong();
241 + previousMap = typedStatistics.previousLong();
242 + Load longLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
243 + TypedFlowEntryWithLoad.longPollInterval());
244 +
245 + currentMap = typedStatistics.currentUnknown();
246 + previousMap = typedStatistics.previousUnknown();
247 + Load unknownLoad = new DefaultLoad(aggregateBytesMap(currentMap), aggregateBytesMap(previousMap),
248 + TypedFlowEntryWithLoad.avgPollInterval());
249 +
250 + return new SummaryFlowEntryWithLoad(cp, totalLoad, immediateLoad, shortLoad, midLoad, longLoad, unknownLoad);
251 + }
252 +
253 + private List<TypedFlowEntryWithLoad> loadAllPortInternal(ConnectPoint cp,
254 + TypedStoredFlowEntry.FlowLiveType liveType,
255 + Instruction.Type instType) {
256 + checkPermission(STATISTIC_READ);
257 +
258 + List<TypedFlowEntryWithLoad> retTFEL = new ArrayList<>();
259 +
260 + Set<FlowEntry> currentStats;
261 + Set<FlowEntry> previousStats;
262 +
263 + TypedStatistics typedStatistics;
264 + synchronized (flowStatisticStore) {
265 + currentStats = flowStatisticStore.getCurrentFlowStatistic(cp);
266 + if (currentStats == null) {
267 + return retTFEL;
268 + }
269 + previousStats = flowStatisticStore.getPreviousFlowStatistic(cp);
270 + if (previousStats == null) {
271 + return retTFEL;
272 + }
273 + // copy to local flow entry set
274 + typedStatistics = new TypedStatistics(currentStats, previousStats);
275 +
276 + // Check for validity of this stats data
277 + checkLoadValidity(currentStats, previousStats);
278 + }
279 +
280 + // current and previous set is not empty!
281 + boolean isAllLiveType = (liveType == null ? true : false); // null is all live type
282 + boolean isAllInstType = (instType == null ? true : false); // null is all inst type
283 +
284 + Map<FlowRule, TypedStoredFlowEntry> currentMap;
285 + Map<FlowRule, TypedStoredFlowEntry> previousMap;
286 +
287 + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.IMMEDIATE_FLOW) {
288 + currentMap = typedStatistics.currentImmediate();
289 + previousMap = typedStatistics.previousImmediate();
290 +
291 + List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
292 + isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());
293 + if (fel.size() > 0) {
294 + retTFEL.addAll(fel);
295 + }
296 + }
297 +
298 + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.SHORT_FLOW) {
299 + currentMap = typedStatistics.currentShort();
300 + previousMap = typedStatistics.previousShort();
301 +
302 + List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
303 + isAllInstType, instType, TypedFlowEntryWithLoad.shortPollInterval());
304 + if (fel.size() > 0) {
305 + retTFEL.addAll(fel);
306 + }
307 + }
308 +
309 + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.MID_FLOW) {
310 + currentMap = typedStatistics.currentMid();
311 + previousMap = typedStatistics.previousMid();
312 +
313 + List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
314 + isAllInstType, instType, TypedFlowEntryWithLoad.midPollInterval());
315 + if (fel.size() > 0) {
316 + retTFEL.addAll(fel);
317 + }
318 + }
319 +
320 + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.LONG_FLOW) {
321 + currentMap = typedStatistics.currentLong();
322 + previousMap = typedStatistics.previousLong();
323 +
324 + List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
325 + isAllInstType, instType, TypedFlowEntryWithLoad.longPollInterval());
326 + if (fel.size() > 0) {
327 + retTFEL.addAll(fel);
328 + }
329 + }
330 +
331 + if (isAllLiveType || liveType == TypedStoredFlowEntry.FlowLiveType.UNKNOWN_FLOW) {
332 + currentMap = typedStatistics.currentUnknown();
333 + previousMap = typedStatistics.previousUnknown();
334 +
335 + List<TypedFlowEntryWithLoad> fel = typedFlowEntryLoadByInstInternal(cp, currentMap, previousMap,
336 + isAllInstType, instType, TypedFlowEntryWithLoad.avgPollInterval());
337 + if (fel.size() > 0) {
338 + retTFEL.addAll(fel);
339 + }
340 + }
341 +
342 + return retTFEL;
343 + }
344 +
345 + private List<TypedFlowEntryWithLoad> typedFlowEntryLoadByInstInternal(ConnectPoint cp,
346 + Map<FlowRule, TypedStoredFlowEntry> currentMap,
347 + Map<FlowRule, TypedStoredFlowEntry> previousMap,
348 + boolean isAllInstType,
349 + Instruction.Type instType,
350 + int liveTypePollInterval) {
351 + List<TypedFlowEntryWithLoad> fel = new ArrayList<>();
352 +
353 + for (TypedStoredFlowEntry tfe : currentMap.values()) {
354 + if (isAllInstType ||
355 + tfe.treatment().allInstructions().stream().
356 + filter(i -> i.type() == instType).
357 + findAny().isPresent()) {
358 + long currentBytes = tfe.bytes();
359 + long previousBytes = previousMap.getOrDefault(tfe, new DefaultTypedFlowEntry((FlowRule) tfe)).bytes();
360 + Load fLoad = new DefaultLoad(currentBytes, previousBytes, liveTypePollInterval);
361 + fel.add(new TypedFlowEntryWithLoad(cp, tfe, fLoad));
362 + }
363 + }
364 +
365 + return fel;
366 + }
367 +
368 + private List<TypedFlowEntryWithLoad> loadTopnPortInternal(ConnectPoint cp,
369 + TypedStoredFlowEntry.FlowLiveType liveType,
370 + Instruction.Type instType,
371 + int topn) {
372 + List<TypedFlowEntryWithLoad> fel = loadAllPortInternal(cp, liveType, instType);
373 +
374 + // Sort with descending order of load
375 + List<TypedFlowEntryWithLoad> tfel =
376 + fel.stream().sorted(Comparators.TYPEFLOWENTRY_WITHLOAD_COMPARATOR).
377 + limit(topn).collect(Collectors.toList());
378 +
379 + return tfel;
380 + }
381 +
382 + private long aggregateBytesSet(Set<FlowEntry> setFE) {
383 + return setFE.stream().mapToLong(FlowEntry::bytes).sum();
384 + }
385 +
386 + private long aggregateBytesMap(Map<FlowRule, TypedStoredFlowEntry> mapFE) {
387 + return mapFE.values().stream().mapToLong(FlowEntry::bytes).sum();
388 + }
389 +
390 + /**
391 + * Internal data class holding two set of typed flow entries.
392 + */
393 + private static class TypedStatistics {
394 + private final ImmutableSet<FlowEntry> currentAll;
395 + private final ImmutableSet<FlowEntry> previousAll;
396 +
397 + private final Map<FlowRule, TypedStoredFlowEntry> currentImmediate = new HashMap<>();
398 + private final Map<FlowRule, TypedStoredFlowEntry> previousImmediate = new HashMap<>();
399 +
400 + private final Map<FlowRule, TypedStoredFlowEntry> currentShort = new HashMap<>();
401 + private final Map<FlowRule, TypedStoredFlowEntry> previousShort = new HashMap<>();
402 +
403 + private final Map<FlowRule, TypedStoredFlowEntry> currentMid = new HashMap<>();
404 + private final Map<FlowRule, TypedStoredFlowEntry> previousMid = new HashMap<>();
405 +
406 + private final Map<FlowRule, TypedStoredFlowEntry> currentLong = new HashMap<>();
407 + private final Map<FlowRule, TypedStoredFlowEntry> previousLong = new HashMap<>();
408 +
409 + private final Map<FlowRule, TypedStoredFlowEntry> currentUnknown = new HashMap<>();
410 + private final Map<FlowRule, TypedStoredFlowEntry> previousUnknown = new HashMap<>();
411 +
412 + public TypedStatistics(Set<FlowEntry> current, Set<FlowEntry> previous) {
413 + this.currentAll = ImmutableSet.copyOf(checkNotNull(current));
414 + this.previousAll = ImmutableSet.copyOf(checkNotNull(previous));
415 +
416 + currentAll.forEach(fe -> {
417 + TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);
418 +
419 + switch (tfe.flowLiveType()) {
420 + case IMMEDIATE_FLOW:
421 + currentImmediate.put(fe, tfe);
422 + break;
423 + case SHORT_FLOW:
424 + currentShort.put(fe, tfe);
425 + break;
426 + case MID_FLOW:
427 + currentMid.put(fe, tfe);
428 + break;
429 + case LONG_FLOW:
430 + currentLong.put(fe, tfe);
431 + break;
432 + default:
433 + currentUnknown.put(fe, tfe);
434 + break;
435 + }
436 + });
437 +
438 + previousAll.forEach(fe -> {
439 + TypedStoredFlowEntry tfe = TypedFlowEntryWithLoad.newTypedStoredFlowEntry(fe);
440 +
441 + switch (tfe.flowLiveType()) {
442 + case IMMEDIATE_FLOW:
443 + if (currentImmediate.containsKey(fe)) {
444 + previousImmediate.put(fe, tfe);
445 + } else if (currentShort.containsKey(fe)) {
446 + previousShort.put(fe, tfe);
447 + } else if (currentMid.containsKey(fe)) {
448 + previousMid.put(fe, tfe);
449 + } else if (currentLong.containsKey(fe)) {
450 + previousLong.put(fe, tfe);
451 + } else {
452 + previousUnknown.put(fe, tfe);
453 + }
454 + break;
455 + case SHORT_FLOW:
456 + if (currentShort.containsKey(fe)) {
457 + previousShort.put(fe, tfe);
458 + } else if (currentMid.containsKey(fe)) {
459 + previousMid.put(fe, tfe);
460 + } else if (currentLong.containsKey(fe)) {
461 + previousLong.put(fe, tfe);
462 + } else {
463 + previousUnknown.put(fe, tfe);
464 + }
465 + break;
466 + case MID_FLOW:
467 + if (currentMid.containsKey(fe)) {
468 + previousMid.put(fe, tfe);
469 + } else if (currentLong.containsKey(fe)) {
470 + previousLong.put(fe, tfe);
471 + } else {
472 + previousUnknown.put(fe, tfe);
473 + }
474 + break;
475 + case LONG_FLOW:
476 + if (currentLong.containsKey(fe)) {
477 + previousLong.put(fe, tfe);
478 + } else {
479 + previousUnknown.put(fe, tfe);
480 + }
481 + break;
482 + default:
483 + previousUnknown.put(fe, tfe);
484 + break;
485 + }
486 + });
487 + }
488 +
489 + /**
490 + * Returns flow entries as the current value.
491 + *
492 + * @return flow entries as the current value
493 + */
494 + public ImmutableSet<FlowEntry> current() {
495 + return currentAll;
496 + }
497 +
498 + /**
499 + * Returns flow entries as the previous value.
500 + *
501 + * @return flow entries as the previous value
502 + */
503 + public ImmutableSet<FlowEntry> previous() {
504 + return previousAll;
505 + }
506 +
507 + public Map<FlowRule, TypedStoredFlowEntry> currentImmediate() {
508 + return currentImmediate;
509 + }
510 + public Map<FlowRule, TypedStoredFlowEntry> previousImmediate() {
511 + return previousImmediate;
512 + }
513 + public Map<FlowRule, TypedStoredFlowEntry> currentShort() {
514 + return currentShort;
515 + }
516 + public Map<FlowRule, TypedStoredFlowEntry> previousShort() {
517 + return previousShort;
518 + }
519 + public Map<FlowRule, TypedStoredFlowEntry> currentMid() {
520 + return currentMid;
521 + }
522 + public Map<FlowRule, TypedStoredFlowEntry> previousMid() {
523 + return previousMid;
524 + }
525 + public Map<FlowRule, TypedStoredFlowEntry> currentLong() {
526 + return currentLong;
527 + }
528 + public Map<FlowRule, TypedStoredFlowEntry> previousLong() {
529 + return previousLong;
530 + }
531 + public Map<FlowRule, TypedStoredFlowEntry> currentUnknown() {
532 + return currentUnknown;
533 + }
534 + public Map<FlowRule, TypedStoredFlowEntry> previousUnknown() {
535 + return previousUnknown;
536 + }
537 +
538 + /**
539 + * Validates values are not empty.
540 + *
541 + * @return false if either of the sets is empty. Otherwise, true.
542 + */
543 + public boolean isValid() {
544 + return !(currentAll.isEmpty() || previousAll.isEmpty());
545 + }
546 +
547 + @Override
548 + public int hashCode() {
549 + return Objects.hash(currentAll, previousAll);
550 + }
551 +
552 + @Override
553 + public boolean equals(Object obj) {
554 + if (this == obj) {
555 + return true;
556 + }
557 + if (!(obj instanceof TypedStatistics)) {
558 + return false;
559 + }
560 + final TypedStatistics other = (TypedStatistics) obj;
561 + return Objects.equals(this.currentAll, other.currentAll) &&
562 + Objects.equals(this.previousAll, other.previousAll);
563 + }
564 +
565 + @Override
566 + public String toString() {
567 + return MoreObjects.toStringHelper(this)
568 + .add("current", currentAll)
569 + .add("previous", previousAll)
570 + .toString();
571 + }
572 + }
573 +
574 + private void checkLoadValidity(Set<FlowEntry> current, Set<FlowEntry> previous) {
575 + current.stream().forEach(c -> {
576 + FlowEntry f = previous.stream().filter(p -> c.equals(p)).
577 + findAny().orElse(null);
578 + if (f != null && c.bytes() < f.bytes()) {
579 + log.debug("FlowStatisticManager:checkLoadValidity():" +
580 + "Error: " + c + " :Previous bytes=" + f.bytes() +
581 + " is larger than current bytes=" + c.bytes() + " !!!");
582 + }
583 + });
584 +
585 + }
586 +
587 + /**
588 + * Creates a predicate that checks the instruction type of a flow entry is the same as
589 + * the specified instruction type.
590 + *
591 + * @param instType instruction type to be checked
592 + * @return predicate
593 + */
594 + private static Predicate<FlowEntry> hasInstructionType(Instruction.Type instType) {
595 + return new Predicate<FlowEntry>() {
596 + @Override
597 + public boolean apply(FlowEntry flowEntry) {
598 + List<Instruction> allInstructions = flowEntry.treatment().allInstructions();
599 +
600 + return allInstructions.stream().filter(i -> i.type() == instType).findAny().isPresent();
601 + }
602 + };
603 + }
604 +
605 + /**
606 + * Internal flow rule event listener for FlowStatisticManager.
607 + */
608 + private class InternalFlowRuleStatsListener implements FlowRuleListener {
609 +
610 + @Override
611 + public void event(FlowRuleEvent event) {
612 + FlowRule rule = event.subject();
613 + switch (event.type()) {
614 + case RULE_ADDED:
615 + if (rule instanceof FlowEntry) {
616 + flowStatisticStore.addFlowStatistic((FlowEntry) rule);
617 + }
618 + break;
619 + case RULE_UPDATED:
620 + flowStatisticStore.updateFlowStatistic((FlowEntry) rule);
621 + break;
622 + case RULE_ADD_REQUESTED:
623 + break;
624 + case RULE_REMOVE_REQUESTED:
625 + break;
626 + case RULE_REMOVED:
627 + flowStatisticStore.removeFlowStatistic(rule);
628 + break;
629 + default:
630 + log.warn("Unknown flow rule event {}", event);
631 + }
632 + }
633 + }
634 +}
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 +
17 +package org.onosproject.store.statistic.impl;
18 +
19 +import com.google.common.base.Objects;
20 +import org.apache.felix.scr.annotations.Activate;
21 +import org.apache.felix.scr.annotations.Component;
22 +import org.apache.felix.scr.annotations.Deactivate;
23 +import org.apache.felix.scr.annotations.Reference;
24 +import org.apache.felix.scr.annotations.ReferenceCardinality;
25 +import org.apache.felix.scr.annotations.Service;
26 +import org.onlab.util.KryoNamespace;
27 +import org.onlab.util.Tools;
28 +import org.onosproject.cluster.ClusterService;
29 +import org.onosproject.cluster.NodeId;
30 +import org.onosproject.mastership.MastershipService;
31 +import org.onosproject.net.ConnectPoint;
32 +import org.onosproject.net.DeviceId;
33 +import org.onosproject.net.PortNumber;
34 +import org.onosproject.net.flow.FlowEntry;
35 +import org.onosproject.net.flow.FlowRule;
36 +import org.onosproject.net.flow.instructions.Instruction;
37 +import org.onosproject.net.flow.instructions.Instructions;
38 +import org.onosproject.net.statistic.FlowStatisticStore;
39 +import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
40 +import org.onosproject.store.serializers.KryoNamespaces;
41 +import org.onosproject.store.serializers.KryoSerializer;
42 +import org.slf4j.Logger;
43 +
44 +import java.util.Collections;
45 +import java.util.HashSet;
46 +import java.util.Map;
47 +import java.util.Set;
48 +import java.util.concurrent.ConcurrentHashMap;
49 +import java.util.concurrent.ExecutorService;
50 +import java.util.concurrent.Executors;
51 +import java.util.concurrent.TimeUnit;
52 +
53 +import static org.onlab.util.Tools.groupedThreads;
54 +import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_CURRENT;
55 +import static org.onosproject.store.statistic.impl.StatisticStoreMessageSubjects.GET_PREVIOUS;
56 +import static org.slf4j.LoggerFactory.getLogger;
57 +
58 +/**
59 + * Maintains flow statistics using RPC calls to collect stats from remote instances
60 + * on demand.
61 + */
62 +@Component(immediate = true)
63 +@Service
64 +public class DistributedFlowStatisticStore implements FlowStatisticStore {
65 + private final Logger log = getLogger(getClass());
66 +
67 + // TODO: Make configurable.
68 + private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 4;
69 +
70 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 + protected MastershipService mastershipService;
72 +
73 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 + protected ClusterCommunicationService clusterCommunicator;
75 +
76 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 + protected ClusterService clusterService;
78 +
79 + private Map<ConnectPoint, Set<FlowEntry>> previous =
80 + new ConcurrentHashMap<>();
81 +
82 + private Map<ConnectPoint, Set<FlowEntry>> current =
83 + new ConcurrentHashMap<>();
84 +
85 + protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
86 + @Override
87 + protected void setupKryoPool() {
88 + serializerPool = KryoNamespace.newBuilder()
89 + .register(KryoNamespaces.API)
90 + .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
91 + // register this store specific classes here
92 + .build();
93 + }
94 + };
95 +
96 + private NodeId local;
97 + private ExecutorService messageHandlingExecutor;
98 +
99 + private static final long STATISTIC_STORE_TIMEOUT_MILLIS = 3000;
100 +
101 + @Activate
102 + public void activate() {
103 + local = clusterService.getLocalNode().id();
104 +
105 + messageHandlingExecutor = Executors.newFixedThreadPool(
106 + MESSAGE_HANDLER_THREAD_POOL_SIZE,
107 + groupedThreads("onos/store/statistic", "message-handlers"));
108 +
109 + clusterCommunicator.addSubscriber(
110 + GET_CURRENT, SERIALIZER::decode, this::getCurrentStatisticInternal, SERIALIZER::encode,
111 + messageHandlingExecutor);
112 +
113 + clusterCommunicator.addSubscriber(
114 + GET_CURRENT, SERIALIZER::decode, this::getPreviousStatisticInternal, SERIALIZER::encode,
115 + messageHandlingExecutor);
116 +
117 + log.info("Started");
118 + }
119 +
120 + @Deactivate
121 + public void deactivate() {
122 + clusterCommunicator.removeSubscriber(GET_PREVIOUS);
123 + clusterCommunicator.removeSubscriber(GET_CURRENT);
124 + messageHandlingExecutor.shutdown();
125 + log.info("Stopped");
126 + }
127 +
128 + @Override
129 + public synchronized void removeFlowStatistic(FlowRule rule) {
130 + ConnectPoint cp = buildConnectPoint(rule);
131 + if (cp == null) {
132 + return;
133 + }
134 +
135 + // remove this rule if present from current map
136 + current.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
137 +
138 + // remove this on if present from previous map
139 + previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
140 + }
141 +
142 + @Override
143 + public synchronized void addFlowStatistic(FlowEntry rule) {
144 + ConnectPoint cp = buildConnectPoint(rule);
145 + if (cp == null) {
146 + return;
147 + }
148 +
149 + // create one if absent and add this rule
150 + current.putIfAbsent(cp, new HashSet<>());
151 + current.computeIfPresent(cp, (c, e) -> { e.add(rule); return e; });
152 +
153 + // remove previous one if present
154 + previous.computeIfPresent(cp, (c, e) -> { e.remove(rule); return e; });
155 + }
156 +
157 + public synchronized void updateFlowStatistic(FlowEntry rule) {
158 + ConnectPoint cp = buildConnectPoint(rule);
159 + if (cp == null) {
160 + return;
161 + }
162 +
163 + Set<FlowEntry> curr = current.get(cp);
164 + if (curr == null) {
165 + addFlowStatistic(rule);
166 + } else {
167 + FlowEntry f = curr.stream().filter(c -> rule.equals(c)).
168 + findAny().orElse(null);
169 + if (rule.bytes() < f.bytes()) {
170 + log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
171 + " Invalid Flow Update! Will be removed!!" +
172 + " curr flowId=" + Long.toHexString(rule.id().value()) +
173 + ", prev flowId=" + Long.toHexString(f.id().value()) +
174 + ", curr bytes=" + rule.bytes() + ", prev bytes=" + f.bytes() +
175 + ", curr life=" + rule.life() + ", prev life=" + f.life() +
176 + ", curr lastSeen=" + rule.lastSeen() + ", prev lastSeen=" + f.lastSeen());
177 + // something is wrong! invalid flow entry, so delete it
178 + removeFlowStatistic(rule);
179 + return;
180 + }
181 + Set<FlowEntry> prev = previous.get(cp);
182 + if (prev == null) {
183 + prev = new HashSet<>();
184 + previous.put(cp, prev);
185 + }
186 +
187 + // previous one is exist
188 + if (f != null) {
189 + // remove old one and add new one
190 + prev.remove(rule);
191 + if (!prev.add(f)) {
192 + log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
193 + " flowId={}, add failed into previous.",
194 + Long.toHexString(rule.id().value()));
195 + }
196 + }
197 +
198 + // remove old one and add new one
199 + curr.remove(rule);
200 + if (!curr.add(rule)) {
201 + log.debug("DistributedFlowStatisticStore:updateFlowStatistic():" +
202 + " flowId={}, add failed into current.",
203 + Long.toHexString(rule.id().value()));
204 + }
205 + }
206 + }
207 +
208 + @Override
209 + public Set<FlowEntry> getCurrentFlowStatistic(ConnectPoint connectPoint) {
210 + final DeviceId deviceId = connectPoint.deviceId();
211 +
212 + NodeId master = mastershipService.getMasterFor(deviceId);
213 + if (master == null) {
214 + log.warn("No master for {}", deviceId);
215 + return Collections.emptySet();
216 + }
217 +
218 + if (Objects.equal(local, master)) {
219 + return getCurrentStatisticInternal(connectPoint);
220 + } else {
221 + return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive(
222 + connectPoint,
223 + GET_CURRENT,
224 + SERIALIZER::encode,
225 + SERIALIZER::decode,
226 + master),
227 + STATISTIC_STORE_TIMEOUT_MILLIS,
228 + TimeUnit.MILLISECONDS,
229 + Collections.emptySet());
230 + }
231 + }
232 +
233 + private synchronized Set<FlowEntry> getCurrentStatisticInternal(ConnectPoint connectPoint) {
234 + return current.get(connectPoint);
235 + }
236 +
237 + @Override
238 + public Set<FlowEntry> getPreviousFlowStatistic(ConnectPoint connectPoint) {
239 + final DeviceId deviceId = connectPoint.deviceId();
240 +
241 + NodeId master = mastershipService.getMasterFor(deviceId);
242 + if (master == null) {
243 + log.warn("No master for {}", deviceId);
244 + return Collections.emptySet();
245 + }
246 +
247 + if (Objects.equal(local, master)) {
248 + return getPreviousStatisticInternal(connectPoint);
249 + } else {
250 + return Tools.futureGetOrElse(clusterCommunicator.sendAndReceive(
251 + connectPoint,
252 + GET_PREVIOUS,
253 + SERIALIZER::encode,
254 + SERIALIZER::decode,
255 + master),
256 + STATISTIC_STORE_TIMEOUT_MILLIS,
257 + TimeUnit.MILLISECONDS,
258 + Collections.emptySet());
259 + }
260 + }
261 +
262 + private synchronized Set<FlowEntry> getPreviousStatisticInternal(ConnectPoint connectPoint) {
263 + return previous.get(connectPoint);
264 + }
265 +
266 + private ConnectPoint buildConnectPoint(FlowRule rule) {
267 + PortNumber port = getOutput(rule);
268 +
269 + if (port == null) {
270 + return null;
271 + }
272 + ConnectPoint cp = new ConnectPoint(rule.deviceId(), port);
273 + return cp;
274 + }
275 +
276 + private PortNumber getOutput(FlowRule rule) {
277 + for (Instruction i : rule.treatment().allInstructions()) {
278 + if (i.type() == Instruction.Type.OUTPUT) {
279 + Instructions.OutputInstruction out = (Instructions.OutputInstruction) i;
280 + return out.port();
281 + }
282 + if (i.type() == Instruction.Type.DROP) {
283 + return PortNumber.P0;
284 + }
285 + }
286 + return null;
287 + }
288 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -717,25 +717,9 @@ public class NewAdaptiveFlowStatsCollector { ...@@ -717,25 +717,9 @@ public class NewAdaptiveFlowStatsCollector {
717 long curTime = (cTime > 0 ? cTime : System.currentTimeMillis()); 717 long curTime = (cTime > 0 ? cTime : System.currentTimeMillis());
718 // For latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply 718 // For latency adjustment(default=500 millisecond) between FlowStatsRequest and Reply
719 long fromLastSeen = ((curTime - fe.lastSeen() + latencyFlowStatsRequestAndReplyMillis) / 1000); 719 long fromLastSeen = ((curTime - fe.lastSeen() + latencyFlowStatsRequestAndReplyMillis) / 1000);
720 -
721 // fe.life() unit is SECOND! 720 // fe.life() unit is SECOND!
722 long liveTime = fe.life() + fromLastSeen; 721 long liveTime = fe.life() + fromLastSeen;
723 722
724 - // check flow timeout
725 - if (fe.timeout() > calAndPollInterval && fromLastSeen > fe.timeout()) {
726 - if (!fe.isPermanent()) {
727 - log.debug("checkAndMoveLiveFlowInternal, FlowId=" + Long.toHexString(fe.id().value())
728 - + ", liveType=" + fe.flowLiveType()
729 - + ", liveTime=" + liveTime
730 - + ", life=" + fe.life()
731 - + ", fromLastSeen=" + fromLastSeen
732 - + ", timeout=" + fe.timeout()
733 - + ", isPermanent=" + fe.isPermanent()
734 - + " AdaptiveStats collection thread for {}",
735 - sw.getStringId());
736 - return false;
737 - }
738 - }
739 723
740 switch (fe.flowLiveType()) { 724 switch (fe.flowLiveType()) {
741 case IMMEDIATE_FLOW: 725 case IMMEDIATE_FLOW:
......