blob: d34c9edb3e3ed0aaa9482cbd04dce79b7cb14a22 [file] [log] [blame]
Sangsik Yoonf0b3ad82016-08-19 18:47:59 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Sangsik Yoonf0b3ad82016-08-19 18:47:59 +09003 *
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
17package org.onosproject.cli.net;
18
19import org.apache.karaf.shell.commands.Argument;
20import org.apache.karaf.shell.commands.Command;
21import org.apache.karaf.shell.commands.Option;
22import org.onosproject.cli.AbstractShellCommand;
23import org.onosproject.incubator.net.dpi.DpiStatInfo;
24import org.onosproject.incubator.net.dpi.DpiStatistics;
25import org.onosproject.incubator.net.dpi.DpiStatisticsManagerService;
26import org.onosproject.incubator.net.dpi.FlowStatInfo;
27import org.onosproject.incubator.net.dpi.ProtocolStatInfo;
28import org.onosproject.incubator.net.dpi.TrafficStatInfo;
29
30import java.util.List;
31
32import static java.lang.Thread.sleep;
33
34/**
35 * Fetches DPI statistics list.
36 */
37@Command(scope = "onos", name = "dpis",
38 description = "Fetches the DPI result entries that is received from DPI engine server")
39public class DpisListCommand extends AbstractShellCommand {
40 @Argument(index = 0, name = "receivedTime", description = "received time: format 'yyyy-MM-dd HH:mm:ss', "
41 + "ex:'2016-08-30 10:31:20', default = null(latest time)",
42 required = false, multiValued = false)
43 String receivedTime = null; // default is latest time
44
45 @Option(name = "-l", aliases = "--latest",
46 description = "Show the latest dpi stats result entry",
47 required = false, multiValued = false)
48 boolean latest = true; // default
49
50 @Option(name = "-d", aliases = "--detectedProtocols",
51 description = "Show the detected protocols only for each statistic entry",
52 required = false, multiValued = false)
53 boolean dProtocols = false; // default
54
55 @Option(name = "-k", aliases = "--knownFlows",
56 description = "Show the known flows only for each statistic entry",
57 required = false, multiValued = false)
58 boolean kFlows = false; // default
59
60 @Option(name = "-u", aliases = "--unknownFlows",
61 description = "Show the unknown flows only for each statistic entry",
62 required = false, multiValued = false)
63 boolean uFlows = false; // default
64
65 @Option(name = "-a", aliases = "--all",
66 description = "Show the all statistics information in detail for each statistic entry",
67 required = false, multiValued = false)
68 boolean all = false; // default is traffic statistics only display
69
70 @Option(name = "-p", aliases = "--permanent",
71 description = "Show the latest dpi stats result entry permanently at 5 second, use Ctrl+C for quitting",
72 required = false, multiValued = false)
73 boolean permanent = false;
74
75 @Option(name = "-n", aliases = "--lastn",
76 description = "Show the last N Dpi stats result entries, MAX_REQUEST_ENTRY = 100",
77 required = false, multiValued = false)
78 String lastn = null;
79
80 @Option(name = "-P", aliases = "--topnProtocols",
81 description = "Show the topn detected Protocol result entries, MAX_PROTOCOLS_TOPN = 100",
82 required = false, multiValued = false)
83 String topnProtocols = null;
84
85 @Option(name = "-F", aliases = "--topnFlows",
86 description = "Show the topn known and unknown Flows result entries, MAX_FLOWS_TOPN = 100",
87 required = false, multiValued = false)
88 String topnFlows = null;
89
90 private static final int DEFAULT_LASTN = 100;
91 private static final int DEFAULT_TOPNP = -1;
92 private static final int DEFAULT_TOPNF = -1;
93 private static final String NO_DPI_ENTRY_ERROR_MSG = "No DPI statistic entry,"
94 + " please check remote DPI engine is running";
95 private static final String RECEIVED_TIME_ERROR_MSG = NO_DPI_ENTRY_ERROR_MSG + "\n"
96 + " or correct receivedTime format: 'yyyy-MM-dd HH:mm:ss', ex:'2016-08-30 10:31:20'";
97
98 @Override
99 protected void execute() {
100 DpiStatisticsManagerService dsms = get(DpiStatisticsManagerService.class);
101
102 DpiStatistics ds;
103
104 int topnP = DEFAULT_TOPNP;
105 int topnF = DEFAULT_TOPNF;
106
107 if (topnProtocols != null) {
108 topnP = parseIntWithDefault(topnProtocols, DEFAULT_TOPNP);
109 if (topnP <= 0) {
110 print("Invalid detected protocol topn number: 0 < valid number <= 100");
111 return;
112 }
113 }
114
115 if (topnFlows != null) {
116 topnF = parseIntWithDefault(topnFlows, DEFAULT_TOPNF);
117 if (topnF <= 0) {
118 print("Invalid known or unknown flows topn number: 0 < valid number <= 100");
119 return;
120 }
121 }
122
123 boolean isTopn = (topnP > 0 || topnF > 0);
124
125 if (all) {
126 dProtocols = true;
127 kFlows = true;
128 uFlows = true;
129 }
130
131 if (receivedTime != null) {
132 if (isTopn) {
133 ds = dsms.getDpiStatistics(receivedTime, topnP, topnF);
134 } else {
135 ds = dsms.getDpiStatistics(receivedTime);
136 }
137 if (ds == null) {
138 print(RECEIVED_TIME_ERROR_MSG);
139 return;
140 }
141
142 printDpiStatistics(0, ds);
143 } else if (lastn != null) {
144 int lastN = parseIntWithDefault(lastn, DEFAULT_LASTN);
145
146 List<DpiStatistics> dsList;
147 if (isTopn) {
148 dsList = dsms.getDpiStatistics(lastN, topnP, topnF);
149
150 } else {
151 dsList = dsms.getDpiStatistics(lastN);
152 }
153
154 printDpiStatisticsList(dsList);
155 } else if (permanent) {
156 int i = 0;
157 while (true) {
158 try {
159 if (isTopn) {
160 ds = dsms.getDpiStatisticsLatest(topnP, topnF);
161 } else {
162 ds = dsms.getDpiStatisticsLatest();
163 }
164 if (ds == null) {
165 print(NO_DPI_ENTRY_ERROR_MSG);
166 return;
167 }
168
169 printDpiStatistics(i++, ds);
170 sleep(5000);
171 } catch (Exception e) {
172 return;
173 }
174 }
175 } else { // latest == true
176 if (isTopn) {
177 ds = dsms.getDpiStatisticsLatest(topnP, topnF);
178 } else {
179 ds = dsms.getDpiStatisticsLatest();
180 }
181 if (ds == null) {
182 print(NO_DPI_ENTRY_ERROR_MSG);
183 return;
184 }
185
186 printDpiStatistics(0, ds);
187 }
188 }
189
190
191 /**
192 * Parse unsigned integer from input lastn string.
193 *
194 * @param lastN string lastn number
195 * @param defaultN integer default lastn number = 100
196 * @return integer lastN number, defaultN if input format is not a number
197 */
198 private int parseIntWithDefault(String lastN, int defaultN) {
199 try {
200 lastN = lastN.trim();
201 return Integer.parseUnsignedInt(lastN);
202 } catch (NumberFormatException e) {
203 return defaultN;
204 }
205 }
206
207 private void printDpiStatistics(int number, DpiStatistics ds) {
208 if (outputJson()) {
209 printDpiStatisticsJson(number, ds);
210 } else {
211 printDpiStatisticsClass(number, ds);
212 }
213 }
214
215 private void printDpiStatisticsJson(int number, DpiStatistics ds) {
Ray Milkey42b62032018-02-01 11:15:31 -0800216 String index = number < 0 ? " - " : String.format("%5d", number);
Jon Halla3fcf672017-03-28 16:53:22 -0700217 if ("".equals(ds.receivedTime())) {
Sangsik Yoonf0b3ad82016-08-19 18:47:59 +0900218 print("ReceivedTime is null, No valid DPI Statistics!");
219 return;
220 }
221
222 print("<--- (%s) DPI Statistics Time [%s] --->", index, ds.receivedTime());
223 print(" %s", ds.toString());
224 print("<--------------------------------------------------------->");
225 }
226
227 private void printDpiStatisticsClass(int number, DpiStatistics ds) {
228 String printLine = "";
Ray Milkey42b62032018-02-01 11:15:31 -0800229 String index = number < 0 ? " - " : String.format("%5d", number);
Sangsik Yoonf0b3ad82016-08-19 18:47:59 +0900230
231 DpiStatInfo dsi = ds.dpiStatInfo();
232 if (dsi == null) {
233 return;
234 }
235
Jon Halla3fcf672017-03-28 16:53:22 -0700236 if ("".equals(ds.receivedTime())) {
Sangsik Yoonf0b3ad82016-08-19 18:47:59 +0900237 print("ReceivedTime is null, No valid DPI Statistics!");
238 return;
239 }
240
241 print("<--- (%s) DPI Statistics Time [%s] --->", index, ds.receivedTime());
242
243 print("Traffic Statistics:");
244 TrafficStatInfo tsi = dsi.trafficStatistics();
245
246 printLine = String.format(" %-30s %-30s", "ethernet.bytes:" + ":", tsi.ethernetBytes());
247 print("%s", printLine);
248 printLine = String.format(" %-30s %-30s", "discarded.bytes" + ":", tsi.discardedBytes());
249 print("%s", printLine);
250 printLine = String.format(" %-30s %-30s", "ip.packets" + ":", tsi.ipPackets());
251 print("%s", printLine);
252 printLine = String.format(" %-30s %-30s", "total.packets" + ":", tsi.totalPackets());
253 print("%s", printLine);
254 printLine = String.format(" %-30s %-30s", "ip.bytes" + ":", tsi.ipBytes());
255 print("%s", printLine);
256 printLine = String.format(" %-30s %-30s", "avg.pkt.size" + ":", tsi.avgPktSize());
257 print("%s", printLine);
258 printLine = String.format(" %-30s %-30s", "unique.flows" + ":", tsi.uniqueFlows());
259 print("%s", printLine);
260 printLine = String.format(" %-30s %-30s", "tcp.packets" + ":", tsi.tcpPackets());
261 print("%s", printLine);
262 printLine = String.format(" %-30s %-30s", "udp.packets" + ":", tsi.tcpPackets());
263 print("%s", printLine);
264 printLine = String.format(" %-30s %-30s", "dpi.throughput.pps" + ":",
265 tsi.dpiThroughputPps() + " pps");
266 print("%s", printLine);
267 printLine = String.format(" %-30s %-30s", "dpi.throughput.bps" + ":",
268 tsi.dpiThroughputBps() + " bps");
269 print("%s", printLine);
270 printLine = String.format(" %-30s %-30s", "traffic.throughput.pps" + ":",
271 tsi.trafficThroughputPps() + " pps");
272 print("%s", printLine);
273 printLine = String.format(" %-30s %-30s", "traffic.throughput.bps" + ":",
274 tsi.trafficThroughputBps() + " bps");
275 print("%s", printLine);
276 printLine = String.format(" %-30s %-30s", "traffic.duration.sec" + ":",
277 tsi.trafficDurationSec() + " sec");
278 print("%s", printLine);
279 printLine = String.format(" %-30s %-30s", "guessed.flow.protos" + ":", tsi.guessedFlowProtos());
280 print("%s", printLine);
281
282 if (dProtocols || topnProtocols != null) {
283 print("");
284 print("Detected Protocols:");
285 List<ProtocolStatInfo> psiList = dsi.detectedProtos();
286 if (psiList != null) {
287 psiList.forEach(psi -> print(makeProtocolString(psi)));
288 }
289 }
290
291 List<FlowStatInfo> fsiList;
292 if (kFlows || topnFlows != null) {
293 print("");
294 print("Known Flows:");
295 fsiList = dsi.knownFlows();
296 if (fsiList != null) {
297 for (int i = 0; i < fsiList.size(); i++) {
298 print(makeFlowString(fsiList.get(i), i));
299 }
300 }
301 }
302
303 if (uFlows || topnFlows != null) {
304 print("");
305 print("Unknown Flows:");
306 fsiList = dsi.unknownFlows();
307 if (fsiList != null) {
308 for (int i = 0; i < fsiList.size(); i++) {
309 print(makeFlowString(fsiList.get(i), i));
310 }
311 }
312 }
313
314 print("<--------------------------------------------------------->");
315 }
316
317 private void printDpiStatisticsList(List<DpiStatistics> dsList) {
318 if (outputJson()) {
319 printDpiStatisticsListJson(dsList);
320 } else {
321 printDpiStatisticsListClass(dsList);
322 }
323 }
324
325 private void printDpiStatisticsListJson(List<DpiStatistics> dsList) {
326 for (int i = 0; i < dsList.size(); i++) {
327 printDpiStatisticsJson(i, dsList.get(i));
328 }
329 }
330
331 private void printDpiStatisticsListClass(List<DpiStatistics> dsList) {
332 for (int i = 0; i < dsList.size(); i++) {
333 printDpiStatisticsClass(i, dsList.get(i));
334 }
335 }
336
337 private String makeProtocolString(ProtocolStatInfo psi) {
338 StringBuffer sb = new StringBuffer(" ");
339
340 sb.append(String.format("%-20s", psi.name()));
341 sb.append(String.format(" %s: %-20s", "packets", psi.packets()));
342 sb.append(String.format(" %s: %-20s", "bytes", psi.bytes()));
343 sb.append(String.format(" %s: %-20s", "flows", psi.flows()));
344
345 return sb.toString();
346 }
347
348 private String makeFlowString(FlowStatInfo fsi, int index) {
349 StringBuffer sb = new StringBuffer(" ");
350
351 sb.append(String.format("%-8d ", index));
352 sb.append(String.format("%s ", fsi.protocol()));
353 sb.append(String.format("%s", fsi.hostAName()));
354 sb.append(String.format(":%s", fsi.hostAPort()));
355 sb.append(String.format(" <-> %s", fsi.hostBName()));
356 sb.append(String.format(":%s", fsi.hostBPort()));
357 sb.append(String.format(" [proto: %d", fsi.detectedProtocol()));
358 sb.append(String.format("/%s]", fsi.detectedProtocolName()));
359 sb.append(String.format(" [%s pkts/", fsi.packets()));
360 sb.append(String.format("%s bytes]", fsi.bytes()));
361 String serverHostName = fsi.hostServerName();
Jon Halla3fcf672017-03-28 16:53:22 -0700362 if (serverHostName != null && !"".equals(serverHostName)) {
Sangsik Yoonf0b3ad82016-08-19 18:47:59 +0900363 sb.append(String.format("[Host: %s]", serverHostName));
364 }
365
366 return sb.toString();
367 }
368}