/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.cli.net; import org.apache.karaf.shell.commands.Argument; import org.apache.karaf.shell.commands.Command; import org.apache.karaf.shell.commands.Option; import org.onosproject.cli.AbstractShellCommand; import org.onosproject.incubator.net.dpi.DpiStatInfo; import org.onosproject.incubator.net.dpi.DpiStatistics; import org.onosproject.incubator.net.dpi.DpiStatisticsManagerService; import org.onosproject.incubator.net.dpi.FlowStatInfo; import org.onosproject.incubator.net.dpi.ProtocolStatInfo; import org.onosproject.incubator.net.dpi.TrafficStatInfo; import java.util.List; import static java.lang.Thread.sleep; /** * Fetches DPI statistics list. */ @Command(scope = "onos", name = "dpis", description = "Fetches the DPI result entries that is received from DPI engine server") public class DpisListCommand extends AbstractShellCommand { @Argument(index = 0, name = "receivedTime", description = "received time: format 'yyyy-MM-dd HH:mm:ss', " + "ex:'2016-08-30 10:31:20', default = null(latest time)", required = false, multiValued = false) String receivedTime = null; // default is latest time @Option(name = "-l", aliases = "--latest", description = "Show the latest dpi stats result entry", required = false, multiValued = false) boolean latest = true; // default @Option(name = "-d", aliases = "--detectedProtocols", description = "Show the detected protocols only for each statistic entry", required = false, multiValued = false) boolean dProtocols = false; // default @Option(name = "-k", aliases = "--knownFlows", description = "Show the known flows only for each statistic entry", required = false, multiValued = false) boolean kFlows = false; // default @Option(name = "-u", aliases = "--unknownFlows", description = "Show the unknown flows only for each statistic entry", required = false, multiValued = false) boolean uFlows = false; // default @Option(name = "-a", aliases = "--all", description = "Show the all statistics information in detail for each statistic entry", required = false, multiValued = false) boolean all = false; // default is traffic statistics only display @Option(name = "-p", aliases = "--permanent", description = "Show the latest dpi stats result entry permanently at 5 second, use Ctrl+C for quitting", required = false, multiValued = false) boolean permanent = false; @Option(name = "-n", aliases = "--lastn", description = "Show the last N Dpi stats result entries, MAX_REQUEST_ENTRY = 100", required = false, multiValued = false) String lastn = null; @Option(name = "-P", aliases = "--topnProtocols", description = "Show the topn detected Protocol result entries, MAX_PROTOCOLS_TOPN = 100", required = false, multiValued = false) String topnProtocols = null; @Option(name = "-F", aliases = "--topnFlows", description = "Show the topn known and unknown Flows result entries, MAX_FLOWS_TOPN = 100", required = false, multiValued = false) String topnFlows = null; private static final int DEFAULT_LASTN = 100; private static final int DEFAULT_TOPNP = -1; private static final int DEFAULT_TOPNF = -1; private static final String NO_DPI_ENTRY_ERROR_MSG = "No DPI statistic entry," + " please check remote DPI engine is running"; private static final String RECEIVED_TIME_ERROR_MSG = NO_DPI_ENTRY_ERROR_MSG + "\n" + " or correct receivedTime format: 'yyyy-MM-dd HH:mm:ss', ex:'2016-08-30 10:31:20'"; @Override protected void execute() { DpiStatisticsManagerService dsms = get(DpiStatisticsManagerService.class); DpiStatistics ds; int topnP = DEFAULT_TOPNP; int topnF = DEFAULT_TOPNF; if (topnProtocols != null) { topnP = parseIntWithDefault(topnProtocols, DEFAULT_TOPNP); if (topnP <= 0) { print("Invalid detected protocol topn number: 0 < valid number <= 100"); return; } } if (topnFlows != null) { topnF = parseIntWithDefault(topnFlows, DEFAULT_TOPNF); if (topnF <= 0) { print("Invalid known or unknown flows topn number: 0 < valid number <= 100"); return; } } boolean isTopn = (topnP > 0 || topnF > 0); if (all) { dProtocols = true; kFlows = true; uFlows = true; } if (receivedTime != null) { if (isTopn) { ds = dsms.getDpiStatistics(receivedTime, topnP, topnF); } else { ds = dsms.getDpiStatistics(receivedTime); } if (ds == null) { print(RECEIVED_TIME_ERROR_MSG); return; } printDpiStatistics(0, ds); } else if (lastn != null) { int lastN = parseIntWithDefault(lastn, DEFAULT_LASTN); List<DpiStatistics> dsList; if (isTopn) { dsList = dsms.getDpiStatistics(lastN, topnP, topnF); } else { dsList = dsms.getDpiStatistics(lastN); } printDpiStatisticsList(dsList); } else if (permanent) { int i = 0; while (true) { try { if (isTopn) { ds = dsms.getDpiStatisticsLatest(topnP, topnF); } else { ds = dsms.getDpiStatisticsLatest(); } if (ds == null) { print(NO_DPI_ENTRY_ERROR_MSG); return; } printDpiStatistics(i++, ds); sleep(5000); } catch (Exception e) { return; } } } else { // latest == true if (isTopn) { ds = dsms.getDpiStatisticsLatest(topnP, topnF); } else { ds = dsms.getDpiStatisticsLatest(); } if (ds == null) { print(NO_DPI_ENTRY_ERROR_MSG); return; } printDpiStatistics(0, ds); } } /** * Parse unsigned integer from input lastn string. * * @param lastN string lastn number * @param defaultN integer default lastn number = 100 * @return integer lastN number, defaultN if input format is not a number */ private int parseIntWithDefault(String lastN, int defaultN) { try { lastN = lastN.trim(); return Integer.parseUnsignedInt(lastN); } catch (NumberFormatException e) { return defaultN; } } private void printDpiStatistics(int number, DpiStatistics ds) { if (outputJson()) { printDpiStatisticsJson(number, ds); } else { printDpiStatisticsClass(number, ds); } } private void printDpiStatisticsJson(int number, DpiStatistics ds) { String index = number < 0 ? String.format(" - ") : String.format("%5d", number); if ("".equals(ds.receivedTime())) { print("ReceivedTime is null, No valid DPI Statistics!"); return; } print("<--- (%s) DPI Statistics Time [%s] --->", index, ds.receivedTime()); print(" %s", ds.toString()); print("<--------------------------------------------------------->"); } private void printDpiStatisticsClass(int number, DpiStatistics ds) { String printLine = ""; String index = number < 0 ? String.format(" - ") : String.format("%5d", number); DpiStatInfo dsi = ds.dpiStatInfo(); if (dsi == null) { return; } if ("".equals(ds.receivedTime())) { print("ReceivedTime is null, No valid DPI Statistics!"); return; } print("<--- (%s) DPI Statistics Time [%s] --->", index, ds.receivedTime()); print("Traffic Statistics:"); TrafficStatInfo tsi = dsi.trafficStatistics(); printLine = String.format(" %-30s %-30s", "ethernet.bytes:" + ":", tsi.ethernetBytes()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "discarded.bytes" + ":", tsi.discardedBytes()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "ip.packets" + ":", tsi.ipPackets()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "total.packets" + ":", tsi.totalPackets()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "ip.bytes" + ":", tsi.ipBytes()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "avg.pkt.size" + ":", tsi.avgPktSize()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "unique.flows" + ":", tsi.uniqueFlows()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "tcp.packets" + ":", tsi.tcpPackets()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "udp.packets" + ":", tsi.tcpPackets()); print("%s", printLine); printLine = String.format(" %-30s %-30s", "dpi.throughput.pps" + ":", tsi.dpiThroughputPps() + " pps"); print("%s", printLine); printLine = String.format(" %-30s %-30s", "dpi.throughput.bps" + ":", tsi.dpiThroughputBps() + " bps"); print("%s", printLine); printLine = String.format(" %-30s %-30s", "traffic.throughput.pps" + ":", tsi.trafficThroughputPps() + " pps"); print("%s", printLine); printLine = String.format(" %-30s %-30s", "traffic.throughput.bps" + ":", tsi.trafficThroughputBps() + " bps"); print("%s", printLine); printLine = String.format(" %-30s %-30s", "traffic.duration.sec" + ":", tsi.trafficDurationSec() + " sec"); print("%s", printLine); printLine = String.format(" %-30s %-30s", "guessed.flow.protos" + ":", tsi.guessedFlowProtos()); print("%s", printLine); if (dProtocols || topnProtocols != null) { print(""); print("Detected Protocols:"); List<ProtocolStatInfo> psiList = dsi.detectedProtos(); if (psiList != null) { psiList.forEach(psi -> print(makeProtocolString(psi))); } } List<FlowStatInfo> fsiList; if (kFlows || topnFlows != null) { print(""); print("Known Flows:"); fsiList = dsi.knownFlows(); if (fsiList != null) { for (int i = 0; i < fsiList.size(); i++) { print(makeFlowString(fsiList.get(i), i)); } } } if (uFlows || topnFlows != null) { print(""); print("Unknown Flows:"); fsiList = dsi.unknownFlows(); if (fsiList != null) { for (int i = 0; i < fsiList.size(); i++) { print(makeFlowString(fsiList.get(i), i)); } } } print("<--------------------------------------------------------->"); } private void printDpiStatisticsList(List<DpiStatistics> dsList) { if (outputJson()) { printDpiStatisticsListJson(dsList); } else { printDpiStatisticsListClass(dsList); } } private void printDpiStatisticsListJson(List<DpiStatistics> dsList) { for (int i = 0; i < dsList.size(); i++) { printDpiStatisticsJson(i, dsList.get(i)); } } private void printDpiStatisticsListClass(List<DpiStatistics> dsList) { for (int i = 0; i < dsList.size(); i++) { printDpiStatisticsClass(i, dsList.get(i)); } } private String makeProtocolString(ProtocolStatInfo psi) { StringBuffer sb = new StringBuffer(" "); sb.append(String.format("%-20s", psi.name())); sb.append(String.format(" %s: %-20s", "packets", psi.packets())); sb.append(String.format(" %s: %-20s", "bytes", psi.bytes())); sb.append(String.format(" %s: %-20s", "flows", psi.flows())); return sb.toString(); } private String makeFlowString(FlowStatInfo fsi, int index) { StringBuffer sb = new StringBuffer(" "); sb.append(String.format("%-8d ", index)); sb.append(String.format("%s ", fsi.protocol())); sb.append(String.format("%s", fsi.hostAName())); sb.append(String.format(":%s", fsi.hostAPort())); sb.append(String.format(" <-> %s", fsi.hostBName())); sb.append(String.format(":%s", fsi.hostBPort())); sb.append(String.format(" [proto: %d", fsi.detectedProtocol())); sb.append(String.format("/%s]", fsi.detectedProtocolName())); sb.append(String.format(" [%s pkts/", fsi.packets())); sb.append(String.format("%s bytes]", fsi.bytes())); String serverHostName = fsi.hostServerName(); if (serverHostName != null && !"".equals(serverHostName)) { sb.append(String.format("[Host: %s]", serverHostName)); } return sb.toString(); } }