Detangling incubator: virtual nets, tunnels, resource labels, oh my
- virtual networking moved to /apps/virtual; with CLI & REST API
- tunnels and labels moved to /apps/tunnel; with CLI & REST API; UI disabled for now
- protobuf/models moved to /core/protobuf/models
- defunct grpc/rpc registry stuff left under /graveyard
- compile dependencies on /incubator moved to respective modules for compilation
- run-time dependencies will need to be re-tested for dependent apps
- /graveyard will be removed in not-too-distant future
Change-Id: I0a0b995c635487edcf95a352f50dd162186b0b39
diff --git a/apps/dpistats/app/BUILD b/apps/dpistats/app/BUILD
new file mode 100644
index 0000000..f075daa
--- /dev/null
+++ b/apps/dpistats/app/BUILD
@@ -0,0 +1,16 @@
+COMPILE_DEPS = CORE_DEPS + JACKSON + REST + CLI + [
+ "//apps/dpistats/api:onos-apps-dpistats-api",
+]
+
+TEST_DEPS = TEST_ADAPTERS
+
+osgi_jar_with_tests(
+ api_description = "REST API for DPI Stats",
+ api_package = "org.onosproject.incubator.net.dpi",
+ api_title = "DPI Stats",
+ api_version = "1.0",
+ karaf_command_packages = ["org.onosproject.incubator.net.dpi"],
+ test_deps = TEST_DEPS,
+ visibility = ["//visibility:public"],
+ deps = COMPILE_DEPS,
+)
diff --git a/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpiStatisticsManager.java b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpiStatisticsManager.java
new file mode 100644
index 0000000..f1fb721
--- /dev/null
+++ b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpiStatisticsManager.java
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.incubator.net.dpi.impl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+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 org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.SortedMap;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static java.lang.Thread.sleep;
+import static org.onlab.util.Tools.groupedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * DPI Statistics Manager.
+ */
+@Component(immediate = true, service = DpiStatisticsManagerService.class)
+public class DpiStatisticsManager implements DpiStatisticsManagerService {
+
+ private ServerSocket serverSocket;
+ private static int port = 11990; // socket server listening port
+
+ private final Logger log = getLogger(getClass());
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected CoreService coreService;
+
+ private ApplicationId appId;
+
+ private final ExecutorService dpiListenerThread =
+ Executors.newSingleThreadExecutor(groupedThreads("onos/apps/dpi", "dpi-listener"));
+
+ DpiStatisticsListener dpiStatisticsListener = null;
+
+ // 31*2(month)*24(hour)*3600(second)/5(second)
+ private static final int MAX_DPI_STATISTICS_ENTRY = 1071360;
+
+ private SortedMap<String, DpiStatistics> dpiStatisticsMap =
+ new TreeMap<>(new MapComparator());
+
+ private long convertTimeToLong(String timeString) {
+ long timeLong = 0;
+
+ try {
+ // Time format: yyyy-MM-dd HH:mm:ss, Time Zone: GMT
+ SimpleDateFormat df = new SimpleDateFormat(DATE_FMT, Locale.KOREA);
+ df.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
+
+ timeLong = df.parse(timeString).getTime();
+ } catch (ParseException e) {
+ log.error("Time parse error! Exception={}", e.toString());
+ }
+
+ return timeLong;
+ }
+
+ private static final String DATE_FMT = "yyyy-MM-dd HH:mm:ss";
+ private static final String TIME_ZONE = "GMT";
+
+ public static final int MAX_DPI_STATISTICS_REQUEST = 100;
+ public static final int MAX_DPI_STATISTICS_TOPN = 100;
+
+ @Activate
+ public void activate(ComponentContext context) {
+ appId = coreService.registerApplication("org.onosproject.dpi");
+
+// registerCodec(DpiStatistics.class, new DpiStatisticsCodec());
+// registerCodec(DpiStatInfo.class, new DpiStatInfoCodec());
+// registerCodec(TrafficStatInfo.class, new TrafficStatInfoCodec());
+// registerCodec(ProtocolStatInfo.class, new ProtocolStatInfoCodec());
+// registerCodec(FlowStatInfo.class, new FlowStatInfoCodec());
+
+ dpiStatisticsListener = new DpiStatisticsListener();
+ dpiListenerThread.execute(dpiStatisticsListener);
+
+ log.info("Started", appId.id());
+ }
+
+ @Deactivate
+ public void deactivate() {
+ log.info("Deactivated...");
+ dpiListenerThread.shutdownNow();
+ log.info("Stopped");
+ }
+
+ @Override
+ public DpiStatistics getDpiStatisticsLatest() {
+ if (dpiStatisticsMap.size() > 0) {
+ return dpiStatisticsMap.get(dpiStatisticsMap.firstKey());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public DpiStatistics getDpiStatisticsLatest(int topnProtocols, int topnFlows) {
+ DpiStatistics ds, topnDs;
+
+ ds = getDpiStatisticsLatest();
+ topnDs = processTopn(ds, topnProtocols, topnFlows);
+
+ return topnDs;
+ }
+
+ @Override
+ public List<DpiStatistics> getDpiStatistics(int lastN) {
+ List<DpiStatistics> dsList = new ArrayList<>();
+ DpiStatistics ds;
+
+ if (lastN > MAX_DPI_STATISTICS_REQUEST) {
+ lastN = MAX_DPI_STATISTICS_REQUEST;
+ }
+
+ SortedMap tempMap = new TreeMap(new MapComparator());
+ tempMap.putAll(dpiStatisticsMap);
+
+ for (int i = 0; i < lastN && i < tempMap.size(); i++) {
+ ds = (DpiStatistics) tempMap.get(tempMap.firstKey());
+ dsList.add(i, new DpiStatistics(ds.receivedTime(), ds.dpiStatInfo()));
+
+ tempMap.remove(tempMap.firstKey());
+ }
+
+ return dsList;
+ }
+
+ @Override
+ public List<DpiStatistics> getDpiStatistics(int lastN, int topnProtocols, int topnFlows) {
+ List<DpiStatistics> dsList;
+ List<DpiStatistics> topnDsList = new ArrayList<>();
+ DpiStatistics ds, topnDs;
+
+ dsList = getDpiStatistics(lastN);
+ for (int i = 0; i < dsList.size(); i++) {
+ ds = dsList.get(i);
+ topnDs = processTopn(ds, topnProtocols, topnFlows);
+ topnDsList.add(i, topnDs);
+ }
+
+ return topnDsList;
+ }
+
+ @Override
+ public DpiStatistics getDpiStatistics(String receivedTime) {
+ DpiStatistics ds;
+
+ if (receivedTime == null) {
+ return null;
+ }
+
+ if (!dpiStatisticsMap.containsKey(receivedTime)) {
+ return null;
+ }
+
+ ds = dpiStatisticsMap.get(receivedTime);
+
+ return ds;
+ }
+
+ @Override
+ public DpiStatistics getDpiStatistics(String receivedTime, int topnProtocols, int topnFlows) {
+ DpiStatistics ds, topnDs;
+
+ ds = getDpiStatistics(receivedTime);
+
+ topnDs = processTopn(ds, topnProtocols, topnFlows);
+
+ return topnDs;
+ }
+
+ @Override
+ public DpiStatistics addDpiStatistics(DpiStatistics ds) {
+ if (ds == null) {
+ return ds;
+ }
+
+ // check the time. The firstKey is lastTime because of descending sorted order
+ if (dpiStatisticsMap.size() > 0) {
+ String lastTime = dpiStatisticsMap.get(dpiStatisticsMap.firstKey()).receivedTime();
+ String inputTime = ds.receivedTime();
+
+ long lastTimeLong = convertTimeToLong(lastTime);
+ long inputTimeLong = convertTimeToLong(inputTime);
+
+ if (lastTimeLong >= inputTimeLong) {
+ return null;
+ }
+ }
+
+ if (dpiStatisticsMap.size() >= MAX_DPI_STATISTICS_ENTRY) {
+ // remove the last (oldest) entry
+ dpiStatisticsMap.remove(dpiStatisticsMap.lastKey());
+ }
+
+ if (dpiStatisticsMap.containsKey(ds.receivedTime())) {
+ log.warn("addDpiStatistics(), {} dpiStatistics is already existing!",
+ ds.receivedTime());
+ return null;
+ }
+
+ dpiStatisticsMap.put(ds.receivedTime(), ds);
+ log.debug("addDpiStatistics: dpiResultJson data[time={}] is added " +
+ "into DpiStatisticsMap size={}.",
+ ds.receivedTime(), dpiStatisticsMap.size());
+
+ return ds;
+ }
+
+ private class MapComparator implements Comparator<String> {
+ @Override
+ public int compare(String rt1, String rt2) {
+ long rt1Long = convertTimeToLong(rt1);
+ long rt2Long = convertTimeToLong(rt2);
+
+ // Descending order
+ if (rt1Long > rt2Long) {
+ return -1;
+ } else if (rt1Long < rt2Long) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ private class ProtocolComparator implements Comparator<ProtocolStatInfo> {
+ @Override
+ public int compare(ProtocolStatInfo p1, ProtocolStatInfo p2) {
+ //Descending order
+ if (p1.bytes() > p2.bytes()) {
+ return -1;
+ } else if (p1.bytes() < p2.bytes()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ private class FlowComparator implements Comparator<FlowStatInfo> {
+ @Override
+ public int compare(FlowStatInfo f1, FlowStatInfo f2) {
+ // Descending order
+ if (f1.bytes() > f2.bytes()) {
+ return -1;
+ } else if (f1.bytes() < f2.bytes()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ private DpiStatistics processTopn(DpiStatistics ds, int topnProtocols, int topnFlows) {
+ if (ds == null) {
+ return null;
+ }
+
+ if (topnProtocols <= 0) {
+ // displays all entries
+ topnProtocols = 0;
+ } else if (topnProtocols > MAX_DPI_STATISTICS_TOPN) {
+ topnProtocols = MAX_DPI_STATISTICS_TOPN;
+ }
+
+ if (topnFlows <= 0) {
+ // displays all entries
+ topnFlows = 0;
+ } else if (topnFlows > MAX_DPI_STATISTICS_TOPN) {
+ topnFlows = MAX_DPI_STATISTICS_TOPN;
+ }
+
+ if (topnProtocols == 0 && topnFlows == 0) {
+ return ds;
+ }
+
+ TrafficStatInfo tsi = ds.dpiStatInfo().trafficStatistics();
+ List<ProtocolStatInfo> psiList;
+ List<FlowStatInfo> kfList;
+ List<FlowStatInfo> ufList;
+
+ List<ProtocolStatInfo> pList = ds.dpiStatInfo().detectedProtos();
+ Collections.sort(pList, new ProtocolComparator());
+ if (topnProtocols > 0 && topnProtocols < pList.size()) {
+ psiList = pList.subList(0, topnProtocols);
+ } else {
+ psiList = pList;
+ }
+
+
+ List<FlowStatInfo> fList = ds.dpiStatInfo().knownFlows();
+ Collections.sort(fList, new FlowComparator());
+ if (topnFlows > 0 && topnFlows < fList.size()) {
+ kfList = fList.subList(0, topnFlows);
+ } else {
+ kfList = fList;
+ }
+
+ fList = ds.dpiStatInfo().unknownFlows();
+ Collections.sort(fList, new FlowComparator());
+ if (topnFlows > 0 && topnFlows < fList.size()) {
+ ufList = fList.subList(0, topnFlows);
+ } else {
+ ufList = fList;
+ }
+
+ DpiStatInfo dsi = new DpiStatInfo();
+ dsi.setTrafficStatistics(tsi);
+ dsi.setDetectedProtos(psiList);
+ dsi.setKnownFlows(kfList);
+ dsi.setUnknownFlows(ufList);
+
+ DpiStatistics retDs = new DpiStatistics(ds.receivedTime(), dsi);
+ return retDs;
+ }
+
+ /**
+ * Receiving DPI Statistics result thread.
+ */
+ private class DpiStatisticsListener implements Runnable {
+ Socket clientSocket = null;
+ BufferedReader in = null;
+ PrintWriter out = null;
+
+ String resultJsonString = null;
+
+ static final int MAX_SLEEP_COUNT = 10;
+ int sleepCount = 0;
+
+ @Override
+ public void run() {
+ log.info("DpiStatisticsListener: Receiving thread started...");
+ receiveDpiResult();
+ }
+
+ private void receiveDpiResult() {
+ try {
+ serverSocket = new ServerSocket(port);
+ } catch (Exception e) {
+ log.error("DpiStatisticsListener: ServerSocket listening error from port={} in localhost, exception={}",
+ port, e.toString());
+ return;
+ }
+
+ try {
+ while (!Thread.currentThread().isInterrupted()) {
+ if (clientSocket == null) {
+ log.info("DpiStatisticsListener: Waiting for accepting from dpi client...");
+ clientSocket = serverSocket.accept();
+ log.info("DpiStatisticsListener: Accepted from dpi client={}",
+ clientSocket.getRemoteSocketAddress().toString());
+
+ in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ out = new PrintWriter(clientSocket.getOutputStream(), true); // For disconnecting check!
+
+ resultJsonString = null;
+ }
+
+ sleepCount = 0;
+ while (!in.ready()) {
+ sleep(1000); // sleep one second.
+ if (out.checkError() || ++sleepCount >= MAX_SLEEP_COUNT) {
+ log.debug("DpiStatisticsListener: server and socket connect is lost...");
+ in.close();
+ in = null;
+ out.close();
+ out = null;
+ clientSocket.close();
+ clientSocket = null;
+
+ break;
+ }
+ }
+
+ if (in != null) {
+ resultJsonString = in.readLine();
+
+ // process the result
+ log.trace("DpiStatisticsListener: resultJsonString={}", resultJsonString);
+ processResultJson(resultJsonString);
+ }
+ }
+ } catch (Exception e) {
+ log.error("DpiStatisticsListener: Exception = {}", e.toString());
+ return;
+ } finally {
+ try {
+ if (serverSocket != null) {
+ if (clientSocket != null) {
+ if (in != null) {
+ in.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ clientSocket.close();
+ //log.debug("DpiResultListener: stop(): Socket close() is done...");
+ }
+ serverSocket.close();
+ //log.debug("DpiResultListener: stop(): Server close() is done...");
+ }
+ } catch (Exception e) {
+ log.error("DpiStatisticsListener: stop(): Server Socket closing error, exception={}",
+ e.toString());
+ }
+ }
+ }
+
+ private void processResultJson(String resultJsonString) {
+ Date tr = new Date(System.currentTimeMillis());
+ SimpleDateFormat df = new SimpleDateFormat(DATE_FMT, Locale.KOREA);
+ df.setTimeZone(TimeZone.getTimeZone(TIME_ZONE));
+
+ String curReceivedTime = new String(df.format(tr));
+ String curResultJson = new String(resultJsonString);
+
+ DpiStatInfo dpiStatInfo;
+ ObjectMapper mapper = new ObjectMapper();
+ try {
+ dpiStatInfo = mapper.readValue(curResultJson, DpiStatInfo.class);
+ } catch (IOException e) {
+ log.error("DpiStatisticsListener: ObjectMapper Exception = {}", e.toString());
+ return;
+ }
+
+ DpiStatistics dpiStatistics = new DpiStatistics(curReceivedTime, dpiStatInfo);
+
+ addDpiStatistics(dpiStatistics);
+ }
+ }
+}
diff --git a/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisListCommand.java b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisListCommand.java
new file mode 100644
index 0000000..33b8396
--- /dev/null
+++ b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisListCommand.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.incubator.net.dpi.impl;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.action.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.
+ */
+@Service
+@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 doExecute() {
+ 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("%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("%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();
+ }
+}
diff --git a/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisWebApplication.java b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisWebApplication.java
new file mode 100644
index 0000000..b90b85d
--- /dev/null
+++ b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisWebApplication.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.incubator.net.dpi.impl;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * DPI Stats REST APIs web application.
+ */
+public class DpisWebApplication extends AbstractWebApplication {
+ @Override
+ public Set<Class<?>> getClasses() {
+ return getClasses(
+ DpisWebResource.class
+ );
+ }
+}
diff --git a/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisWebResource.java b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisWebResource.java
new file mode 100644
index 0000000..51d2eb6
--- /dev/null
+++ b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/DpisWebResource.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.incubator.net.dpi.impl;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+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.rest.AbstractWebResource;
+import org.slf4j.Logger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.onlab.util.Tools.readTreeFromStream;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Query the latest DPI statistics info.
+ */
+
+@Path("dpis")
+public class DpisWebResource extends AbstractWebResource {
+
+ private final Logger log = getLogger(getClass());
+
+ private static final int MAX_TOPN = 100;
+
+ private final DpiStatisticsManagerService service = get(DpiStatisticsManagerService.class);
+
+ public static final Comparator<ProtocolStatInfo> PROTOCOL_STAT_INFO_COMPARATOR =
+ new Comparator<ProtocolStatInfo>() {
+ @Override
+ public int compare(ProtocolStatInfo psi1, ProtocolStatInfo psi2) {
+ long delta = psi1.bytes() - psi2.bytes();
+ return delta == 0 ? 0 : (delta > 0 ? -1 : +1);
+ }
+ };
+
+ public static final Comparator<FlowStatInfo> FLOW_STAT_INFO_COMPARATOR =
+ new Comparator<FlowStatInfo>() {
+ @Override
+ public int compare(FlowStatInfo fsi1, FlowStatInfo fsi2) {
+ long delta = fsi1.bytes() - fsi2.bytes();
+ return delta == 0 ? 0 : (delta > 0 ? -1 : +1);
+ }
+ };
+
+ /**
+ * Gets the latest dpi statistics.
+ *
+ * @param topn max size
+ * @return 200 OK with a dpi statistics
+ * @onos.rsModel DpiStatistics
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getDpisLatest(@QueryParam("topn") int topn) {
+ log.debug("getDpisLatest request with topn={}", topn);
+
+ DpiStatistics ds = service.getDpiStatisticsLatest();
+ DpiStatistics retDs;
+
+ if (ds == null) {
+ retDs = new DpiStatistics("", new DpiStatInfo());
+ } else if (topn <= 0) {
+ retDs = ds;
+ } else {
+ if (topn > MAX_TOPN) {
+ topn = MAX_TOPN;
+ }
+ retDs = new DpiStatistics(ds.receivedTime(),
+ new DpiStatInfo(ds.dpiStatInfo().trafficStatistics()));
+ List<ProtocolStatInfo> psiList = ds.dpiStatInfo().detectedProtos();
+ if (psiList != null) {
+ // sorts protocol list with descending order based on bytes within topn
+ List<ProtocolStatInfo> psiListSorted =
+ psiList.stream().sorted(PROTOCOL_STAT_INFO_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+ retDs.dpiStatInfo().setDetectedProtos(psiListSorted);
+ }
+ List<FlowStatInfo> fsiList = ds.dpiStatInfo().knownFlows();
+ if (fsiList != null) {
+ // sorts known flow list with descending order based on bytes within topn
+ List<FlowStatInfo> fsiListSorted =
+ fsiList.stream().sorted(FLOW_STAT_INFO_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+ retDs.dpiStatInfo().setKnownFlows(fsiListSorted);
+ }
+ fsiList = ds.dpiStatInfo().unknownFlows();
+ if (fsiList != null) {
+ // sorts unknown flow list with descending order based on bytes within topn
+ List<FlowStatInfo> fsiListSorted =
+ fsiList.stream().sorted(FLOW_STAT_INFO_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+ retDs.dpiStatInfo().setUnknownFlows(fsiListSorted);
+ }
+ }
+
+ ObjectNode result = codec(DpiStatistics.class).encode(retDs, this);
+ return ok(result).build();
+
+ }
+
+ /**
+ * Gets the latest traffic statistics only.
+ *
+ * @return 200 OK with a traffic statistics
+ * @onos.rsModel TrafficStatistics
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("traffic")
+ public Response getTrafficStatistics() {
+ log.debug("getTrafficStatistics request");
+
+ DpiStatistics ds = service.getDpiStatisticsLatest();
+ if (ds == null) {
+ ds = new DpiStatistics("", new DpiStatInfo());
+ }
+
+ DpiStatInfo dsi = new DpiStatInfo();
+ dsi.setTrafficStatistics(ds.dpiStatInfo().trafficStatistics());
+ DpiStatistics dsTraffic = new DpiStatistics(ds.receivedTime(), dsi);
+
+ ObjectNode result = codec(DpiStatistics.class).encode(dsTraffic, this);
+ return ok(result).build();
+ }
+
+ /**
+ * Gets the latest detected protocol statistics only.
+ *
+ * @param topn max size
+ * @return 200 OK with a protocol statistics
+ * @onos.rsModel ProtocolStatistics
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("protocols")
+ public Response getDetectedProtocols(@QueryParam("topn") int topn) {
+ log.debug("getDetectedProtocols request with topn={}", topn);
+
+ DpiStatistics ds = service.getDpiStatisticsLatest();
+ DpiStatistics dsProtocol;
+
+ if (ds == null) {
+ dsProtocol = new DpiStatistics("", new DpiStatInfo());
+ } else if (topn <= 0) {
+ DpiStatInfo dsi = new DpiStatInfo();
+ dsi.setDetectedProtos(ds.dpiStatInfo().detectedProtos());
+ dsProtocol = new DpiStatistics(ds.receivedTime(), dsi);
+ } else {
+ if (topn > MAX_TOPN) {
+ topn = MAX_TOPN;
+ }
+ dsProtocol = new DpiStatistics(ds.receivedTime(), new DpiStatInfo());
+ List<ProtocolStatInfo> psiList = ds.dpiStatInfo().detectedProtos();
+ if (psiList != null) {
+ // sorts protocol list with descending order based on bytes within topn
+ List<ProtocolStatInfo> psiListSorted =
+ psiList.stream().sorted(PROTOCOL_STAT_INFO_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+ dsProtocol.dpiStatInfo().setDetectedProtos(psiListSorted);
+ }
+ }
+
+ ObjectNode result = codec(DpiStatistics.class).encode(dsProtocol, this);
+ return ok(result).build();
+ }
+
+ /**
+ * Gets the latest known flows statistics only.
+ *
+ * @param topn max size
+ * @return 200 OK with a known flow statistics
+ * @onos.rsModel KnownFlowStatistics
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("knownFlows")
+ public Response getKnownFlows(@QueryParam("topn") int topn) {
+ log.debug("getKnownFlows request with topn={}", topn);
+
+ DpiStatistics ds = service.getDpiStatisticsLatest();
+ DpiStatistics dsKnownFlows;
+
+ if (ds == null) {
+ dsKnownFlows = new DpiStatistics("", new DpiStatInfo());
+ } else if (topn <= 0) {
+ DpiStatInfo dsi = new DpiStatInfo();
+ dsi.setKnownFlows(ds.dpiStatInfo().knownFlows());
+ dsKnownFlows = new DpiStatistics(ds.receivedTime(), dsi);
+ } else {
+ if (topn > MAX_TOPN) {
+ topn = MAX_TOPN;
+ }
+ dsKnownFlows = new DpiStatistics(ds.receivedTime(), new DpiStatInfo());
+ List<FlowStatInfo> fsiList = ds.dpiStatInfo().knownFlows();
+ if (fsiList != null) {
+ // sorts known flow list with descending order based on bytes within topn
+ List<FlowStatInfo> fsiListSorted =
+ fsiList.stream().sorted(FLOW_STAT_INFO_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+ dsKnownFlows.dpiStatInfo().setKnownFlows(fsiListSorted);
+ }
+ }
+
+ ObjectNode result = codec(DpiStatistics.class).encode(dsKnownFlows, this);
+ return ok(result).build();
+ }
+
+ /**
+ * Gets the latest unknown flows statistics only.
+ *
+ * @param topn max size
+ * @return 200 OK with an unknown flow statistics
+ * @onos.rsModel UnknownFlowStatistics
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("unknownFlows")
+ public Response getUnknownFlows(@QueryParam("topn") int topn) {
+ log.debug("getUnknownFlows request with topn={}", topn);
+
+ DpiStatistics ds = service.getDpiStatisticsLatest();
+ DpiStatistics dsUnknownFlows;
+
+ if (ds == null) {
+ dsUnknownFlows = new DpiStatistics("", new DpiStatInfo());
+ } else if (topn <= 0) {
+ DpiStatInfo dsi = new DpiStatInfo();
+ dsi.setUnknownFlows(ds.dpiStatInfo().unknownFlows());
+ dsUnknownFlows = new DpiStatistics(ds.receivedTime(), dsi);
+ } else {
+ if (topn > 100) {
+ topn = 100;
+ }
+ dsUnknownFlows = new DpiStatistics(ds.receivedTime(), new DpiStatInfo());
+ List<FlowStatInfo> fsiList = ds.dpiStatInfo().unknownFlows();
+ if (fsiList != null) {
+ // sorts unknown flow list with descending order based on bytes within topn
+ List<FlowStatInfo> fsiListSorted =
+ fsiList.stream().sorted(FLOW_STAT_INFO_COMPARATOR).
+ limit(topn).collect(Collectors.toList());
+ dsUnknownFlows.dpiStatInfo().setUnknownFlows(fsiListSorted);
+ }
+ }
+
+ ObjectNode result = codec(DpiStatistics.class).encode(dsUnknownFlows, this);
+ return ok(result).build();
+ }
+
+ /**
+ * Add new dpi statistics entry at the end of list.
+ *
+ * @param stream dpi statistics JSON
+ * @return status of the request - CREATED if the JSON is correct,
+ * BAD_REQUEST if the JSON is invalid
+ * @onos.rsModel DpiStatisticsPost
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response addDpiStatistics(InputStream stream) {
+ ObjectNode result;
+
+ try {
+ ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
+ log.debug("jsonTree={}", jsonTree);
+
+ DpiStatistics ds = codec(DpiStatistics.class).decode(jsonTree, this);
+ if (ds == null) {
+ log.error("Wrong DpiStatistics json format error");
+ }
+
+ // TODO: check the validity of dpi statistics values, specially receivedTime format
+ DpiStatistics added = service.addDpiStatistics(ds);
+
+ result = codec(DpiStatistics.class).encode(added, this);
+ } catch (IOException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ return ok(result).build();
+ }
+}
diff --git a/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/package-info.java b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/package-info.java
new file mode 100644
index 0000000..52f9652
--- /dev/null
+++ b/apps/dpistats/app/src/main/java/org/onosproject/incubator/net/dpi/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Implementation of the dpi statistics service.
+ */
+package org.onosproject.incubator.net.dpi.impl;
\ No newline at end of file
diff --git a/apps/dpistats/app/src/main/resources/definitions/DpiStatistics.json b/apps/dpistats/app/src/main/resources/definitions/DpiStatistics.json
new file mode 100644
index 0000000..d9f3010
--- /dev/null
+++ b/apps/dpistats/app/src/main/resources/definitions/DpiStatistics.json
@@ -0,0 +1,307 @@
+{
+ "type": "object",
+ "title": "dpiStatistics",
+ "required": [
+ "receivedTime",
+ "dpiStatInfo"
+ ],
+ "properties": {
+ "receivedTime": {
+ "type": "string",
+ "example": "2016-06-12 04:05:05"
+ },
+ "dpiStatInfo": {
+ "type": "object",
+ "title": "dpiStatInfo",
+ "required": [
+ "trafficStatistics",
+ "detectedProtos",
+ "knownFlows",
+ "unknownFlow"
+ ],
+ "properties": {
+ "trafficStatistics": {
+ "type": "object",
+ "title": "trafficStatistics",
+ "required": [
+ "ethernetBytes",
+ "discardedBytes",
+ "ipPackets",
+ "totalPackets",
+ "ipBytes",
+ "avgPktSize",
+ "uniqueFlows",
+ "tcpPackets",
+ "udpPackets",
+ "dpiThroughputPps",
+ "dpiThroughputBps",
+ "trafficThroughputPps",
+ "trafficThroughputBps",
+ "trafficDurationSec",
+ "guessedFlowProtos"
+ ],
+ "properties": {
+ "ethernetBytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "discardedBytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "ipPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "totalPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "ipBytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "avgPktSize": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "uniqueFlows": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "tcpPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "udpPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "dpiThroughputPps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "dpiThroughputBps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "trafficThroughputPps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "trafficThroughputBps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "trafficDurationSec": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "guessedFlowProtos": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ }
+ }
+ },
+ "detectedProtos": {
+ "type": "array",
+ "xml": {
+ "name": "detectedProtos",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "title": "protos",
+ "required": [
+ "name",
+ "breed",
+ "packets",
+ "bytes",
+ "flows"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "TCP"
+ },
+ "breed": {
+ "type": "string",
+ "example": "Acceptable"
+ },
+ "packets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "bytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "flows": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ }
+ }
+ }
+ },
+ "knownFlows": {
+ "type": "array",
+ "xml": {
+ "name": "knownFlows",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "title": "knownFlows",
+ "required": [
+ "protocol",
+ "hostAName",
+ "hostAPort",
+ "hostBName",
+ "hostBPort",
+ "detectedProtocol",
+ "detectedProtocolName",
+ "packets",
+ "bytes",
+ "hostServerName"
+ ],
+ "properties": {
+ "protocol": {
+ "type": "string",
+ "example": "TCP"
+ },
+ "hostAName": {
+ "type": "string",
+ "example": "10.0.20.50"
+ },
+ "hostAPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "hostBName": {
+ "type": "string",
+ "example": "10.0.20.10"
+ },
+ "hostBPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 8181
+ },
+ "detectedProtocol": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80
+ },
+ "detectedProtocolName": {
+ "type": "string",
+ "example": "HTTP"
+ },
+ "packets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "bytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "hostSeverName": {
+ "type": "string",
+ "example": "raptor"
+ }
+ }
+ }
+ },
+ "unknownFlows": {
+ "type": "array",
+ "xml": {
+ "name": "unknownFlows",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "title": "unknownFlows",
+ "required": [
+ "protocol",
+ "hostAName",
+ "hostAPort",
+ "hostBName",
+ "hostBPort",
+ "detectedProtocol",
+ "detectedProtocolName",
+ "packets",
+ "bytes",
+ "hostServerName"
+ ],
+ "properties": {
+ "protocol": {
+ "type": "string",
+ "example": "TCP"
+ },
+ "hostAName": {
+ "type": "string",
+ "example": "10.0.20.50"
+ },
+ "hostAPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "hostBName": {
+ "type": "string",
+ "example": "10.0.20.10"
+ },
+ "hostBPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 8181
+ },
+ "detectedProtocol": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80
+ },
+ "detectedProtocolName": {
+ "type": "string",
+ "example": "HTTP"
+ },
+ "packets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "bytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "hostSeverName": {
+ "type": "string",
+ "example": "raptor"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/apps/dpistats/app/src/main/resources/definitions/DpiStatisticsPost.json b/apps/dpistats/app/src/main/resources/definitions/DpiStatisticsPost.json
new file mode 100644
index 0000000..d9f3010
--- /dev/null
+++ b/apps/dpistats/app/src/main/resources/definitions/DpiStatisticsPost.json
@@ -0,0 +1,307 @@
+{
+ "type": "object",
+ "title": "dpiStatistics",
+ "required": [
+ "receivedTime",
+ "dpiStatInfo"
+ ],
+ "properties": {
+ "receivedTime": {
+ "type": "string",
+ "example": "2016-06-12 04:05:05"
+ },
+ "dpiStatInfo": {
+ "type": "object",
+ "title": "dpiStatInfo",
+ "required": [
+ "trafficStatistics",
+ "detectedProtos",
+ "knownFlows",
+ "unknownFlow"
+ ],
+ "properties": {
+ "trafficStatistics": {
+ "type": "object",
+ "title": "trafficStatistics",
+ "required": [
+ "ethernetBytes",
+ "discardedBytes",
+ "ipPackets",
+ "totalPackets",
+ "ipBytes",
+ "avgPktSize",
+ "uniqueFlows",
+ "tcpPackets",
+ "udpPackets",
+ "dpiThroughputPps",
+ "dpiThroughputBps",
+ "trafficThroughputPps",
+ "trafficThroughputBps",
+ "trafficDurationSec",
+ "guessedFlowProtos"
+ ],
+ "properties": {
+ "ethernetBytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "discardedBytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "ipPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "totalPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "ipBytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "avgPktSize": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "uniqueFlows": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "tcpPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "udpPackets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "dpiThroughputPps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "dpiThroughputBps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "trafficThroughputPps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "trafficThroughputBps": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "trafficDurationSec": {
+ "type": "number",
+ "format": "double",
+ "example": 69889.12
+ },
+ "guessedFlowProtos": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ }
+ }
+ },
+ "detectedProtos": {
+ "type": "array",
+ "xml": {
+ "name": "detectedProtos",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "title": "protos",
+ "required": [
+ "name",
+ "breed",
+ "packets",
+ "bytes",
+ "flows"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "example": "TCP"
+ },
+ "breed": {
+ "type": "string",
+ "example": "Acceptable"
+ },
+ "packets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "bytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "flows": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ }
+ }
+ }
+ },
+ "knownFlows": {
+ "type": "array",
+ "xml": {
+ "name": "knownFlows",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "title": "knownFlows",
+ "required": [
+ "protocol",
+ "hostAName",
+ "hostAPort",
+ "hostBName",
+ "hostBPort",
+ "detectedProtocol",
+ "detectedProtocolName",
+ "packets",
+ "bytes",
+ "hostServerName"
+ ],
+ "properties": {
+ "protocol": {
+ "type": "string",
+ "example": "TCP"
+ },
+ "hostAName": {
+ "type": "string",
+ "example": "10.0.20.50"
+ },
+ "hostAPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "hostBName": {
+ "type": "string",
+ "example": "10.0.20.10"
+ },
+ "hostBPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 8181
+ },
+ "detectedProtocol": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80
+ },
+ "detectedProtocolName": {
+ "type": "string",
+ "example": "HTTP"
+ },
+ "packets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "bytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "hostSeverName": {
+ "type": "string",
+ "example": "raptor"
+ }
+ }
+ }
+ },
+ "unknownFlows": {
+ "type": "array",
+ "xml": {
+ "name": "unknownFlows",
+ "wrapped": true
+ },
+ "items": {
+ "type": "object",
+ "title": "unknownFlows",
+ "required": [
+ "protocol",
+ "hostAName",
+ "hostAPort",
+ "hostBName",
+ "hostBPort",
+ "detectedProtocol",
+ "detectedProtocolName",
+ "packets",
+ "bytes",
+ "hostServerName"
+ ],
+ "properties": {
+ "protocol": {
+ "type": "string",
+ "example": "TCP"
+ },
+ "hostAName": {
+ "type": "string",
+ "example": "10.0.20.50"
+ },
+ "hostAPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 9889
+ },
+ "hostBName": {
+ "type": "string",
+ "example": "10.0.20.10"
+ },
+ "hostBPort": {
+ "type": "integer",
+ "format": "int32",
+ "example": 8181
+ },
+ "detectedProtocol": {
+ "type": "integer",
+ "format": "int32",
+ "example": 80
+ },
+ "detectedProtocolName": {
+ "type": "string",
+ "example": "HTTP"
+ },
+ "packets": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "bytes": {
+ "type": "integer",
+ "format": "int64",
+ "example": 69889
+ },
+ "hostSeverName": {
+ "type": "string",
+ "example": "raptor"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}