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/BUILD b/apps/dpistats/BUILD
new file mode 100644
index 0000000..a6d4490
--- /dev/null
+++ b/apps/dpistats/BUILD
@@ -0,0 +1,13 @@
+BUNDLES = [
+ "//apps/dpistats/api:onos-apps-dpistats-api",
+ "//apps/dpistats/app:onos-apps-dpistats-app",
+]
+
+onos_app(
+ app_name = "org.onosproject.dpistats",
+ category = "Traffic Engineering",
+ description = "dpistats Network Subsystem extension",
+ included_bundles = BUNDLES,
+ title = "dpistats Network Subsystem",
+ url = "http://onosproject.org",
+)
diff --git a/apps/dpistats/api/BUILD b/apps/dpistats/api/BUILD
new file mode 100644
index 0000000..c6ca52a
--- /dev/null
+++ b/apps/dpistats/api/BUILD
@@ -0,0 +1,9 @@
+COMPILE_DEPS = CORE_DEPS + JACKSON
+
+TEST_DEPS = TEST_ADAPTERS
+
+osgi_jar_with_tests(
+ test_deps = TEST_DEPS,
+ visibility = ["//visibility:public"],
+ deps = COMPILE_DEPS,
+)
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java
new file mode 100644
index 0000000..afa61f0
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfo.java
@@ -0,0 +1,182 @@
+/*
+ * 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;
+
+import java.util.List;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * DPI statistic information.
+ */
+public class DpiStatInfo {
+ TrafficStatInfo trafficStatistics;
+ List<ProtocolStatInfo> detectedProtos;
+ List<FlowStatInfo> knownFlows;
+ List<FlowStatInfo> unknownFlows;
+
+ /**
+ * Constructor for default DpiStatInfo class.
+ */
+ public DpiStatInfo() {
+ this.trafficStatistics = null;
+ this.detectedProtos = null;
+ this.knownFlows = null;
+ this.unknownFlows = null;
+ }
+
+ /**
+ * Constructor for DpiStatistics class specified with trafficStatInfo.
+ *
+ * @param trafficStatistics traffic statistic information
+ */
+ public DpiStatInfo(TrafficStatInfo trafficStatistics) {
+ this.trafficStatistics = trafficStatistics;
+ this.detectedProtos = null;
+ this.knownFlows = null;
+ this.unknownFlows = null;
+ }
+
+ /**
+ * Constructor for DpiStatistics class specified with trafficStatInfo and detectedProtos.
+ *
+ * @param trafficStatistics traffic statistic information
+ * @param detectedProtos detected protocols statistic information
+ */
+ public DpiStatInfo(TrafficStatInfo trafficStatistics,
+ List<ProtocolStatInfo> detectedProtos) {
+ this.trafficStatistics = trafficStatistics;
+ this.detectedProtos = detectedProtos;
+ this.knownFlows = null;
+ this.unknownFlows = null;
+ }
+
+ /**
+ * Constructor for DpiStatistics class specified with trafficStatInfo, detectedProtos and knownFlows.
+ *
+ * @param trafficStatistics traffic statistic information
+ * @param detectedProtos detected protocols statistic information
+ * @param knownFlows known flows
+ */
+ public DpiStatInfo(TrafficStatInfo trafficStatistics,
+ List<ProtocolStatInfo> detectedProtos,
+ List<FlowStatInfo> knownFlows) {
+ this.trafficStatistics = trafficStatistics;
+ this.detectedProtos = detectedProtos;
+ this.knownFlows = knownFlows;
+ this.unknownFlows = null;
+ }
+
+ /**
+ * Constructor for DpiStatistics class specified with trafficStatInfo, detectedProtos, knownFlows and unknownFlows.
+ *
+ * @param trafficStatistics traffic statistic information
+ * @param detectedProtos detected protocols statistic information
+ * @param knownFlows known flows
+ * @param unknownFlows unknown flows
+ */
+ public DpiStatInfo(TrafficStatInfo trafficStatistics,
+ List<ProtocolStatInfo> detectedProtos,
+ List<FlowStatInfo> knownFlows,
+ List<FlowStatInfo> unknownFlows) {
+ this.trafficStatistics = trafficStatistics;
+ this.detectedProtos = detectedProtos;
+ this.knownFlows = knownFlows;
+ this.unknownFlows = unknownFlows;
+ }
+
+ /**
+ * Returns DPI traffic statistic information.
+ *
+ * @return trafficStatistics
+ */
+ public TrafficStatInfo trafficStatistics() {
+ return trafficStatistics;
+ }
+
+ /**
+ * Returns DPI detected protocols statistic information.
+ *
+ * @return detectedProtos
+ */
+ public List<ProtocolStatInfo> detectedProtos() {
+ return detectedProtos;
+ }
+
+ /**
+ * Returns DPI known flows.
+ *
+ * @return knownFlows
+ */
+ public List<FlowStatInfo> knownFlows() {
+ return knownFlows;
+ }
+
+ /**
+ * Returns DPI unknown flows.
+ *
+ * @return unknownFlows
+ */
+ public List<FlowStatInfo> unknownFlows() {
+ return unknownFlows;
+ }
+
+ /**
+ * Sets the traffic statistic information.
+ *
+ * @param trafficStatistics traffic statistics
+ */
+ public void setTrafficStatistics(TrafficStatInfo trafficStatistics) {
+ this.trafficStatistics = trafficStatistics;
+ }
+
+ /**
+ * Sets the detected protocols statistic information.
+ *
+ * @param detectedProtos detected protocols statistics
+ */
+ public void setDetectedProtos(List<ProtocolStatInfo> detectedProtos) {
+ this.detectedProtos = detectedProtos;
+ }
+
+ /**
+ * Sets the known flows information.
+ *
+ * @param knownFlows known flows
+ */
+ public void setKnownFlows(List<FlowStatInfo> knownFlows) {
+ this.knownFlows = knownFlows;
+ }
+
+ /**
+ * Sets the unknown flows information.
+ *
+ * @param unknownFlows unknown flows
+ */
+ public void setUnknownFlows(List<FlowStatInfo> unknownFlows) {
+ this.unknownFlows = unknownFlows;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("trafficStatistics", trafficStatistics)
+ .add("detectedProtos", detectedProtos)
+ .add("knownFlows", knownFlows)
+ .add("unknownFlows", unknownFlows)
+ .toString();
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java
new file mode 100644
index 0000000..34e246a
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatInfoCodec.java
@@ -0,0 +1,151 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for DpiStatInfo codec.
+ */
+public final class DpiStatInfoCodec extends JsonCodec<DpiStatInfo> {
+
+ private static final String TRAFFIC_STATISTICS = "trafficStatistics";
+ private static final String DETECTED_PROTOS = "detectedProtos";
+ private static final String KNOWN_FLOWS = "knownFlows";
+ private static final String UNKNOWN_FLOWS = "unknownFlows";
+
+ private final Logger log = getLogger(getClass());
+
+ @Override
+ public ObjectNode encode(DpiStatInfo dsi, CodecContext context) {
+ checkNotNull(dsi, "DpiStatInfo cannot be null");
+
+ final ObjectNode result = context.mapper().createObjectNode();
+
+ final JsonCodec<TrafficStatInfo> trafficStatInfoCodec =
+ context.codec(TrafficStatInfo.class);
+
+
+ final TrafficStatInfo tsi = dsi.trafficStatistics();
+ if (tsi != null) {
+ final ObjectNode jsonTrafficStatistics = trafficStatInfoCodec.encode(tsi, context);
+ result.set(TRAFFIC_STATISTICS, jsonTrafficStatistics);
+ }
+
+
+ final List<ProtocolStatInfo> psi = dsi.detectedProtos();
+ if (psi != null) {
+ final ArrayNode jsonDetectedProtos = result.putArray(DETECTED_PROTOS);
+ final JsonCodec<ProtocolStatInfo> protocolStatInfoCodec =
+ context.codec(ProtocolStatInfo.class);
+
+ for (final ProtocolStatInfo protocolStatInfo : psi) {
+ jsonDetectedProtos.add(protocolStatInfoCodec.encode(protocolStatInfo, context));
+ }
+ }
+
+ List<FlowStatInfo> fsi = dsi.knownFlows();
+ if (fsi != null) {
+ final ArrayNode jsonKnownFlows = result.putArray(KNOWN_FLOWS);
+ final JsonCodec<FlowStatInfo> flowStatInfoCodec =
+ context.codec(FlowStatInfo.class);
+
+ for (final FlowStatInfo flowStatInfo : fsi) {
+ jsonKnownFlows.add(flowStatInfoCodec.encode(flowStatInfo, context));
+ }
+ }
+
+ fsi = dsi.unknownFlows();
+ if (fsi != null) {
+ final ArrayNode jsonUnknownFlows = result.putArray(UNKNOWN_FLOWS);
+ final JsonCodec<FlowStatInfo> flowStatInfoCodec =
+ context.codec(FlowStatInfo.class);
+
+ for (final FlowStatInfo flowStatInfo : fsi) {
+ jsonUnknownFlows.add(flowStatInfoCodec.encode(flowStatInfo, context));
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public DpiStatInfo decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ log.debug("trafficStatistics={}, full json={} ", json.get("trafficStatistics"), json);
+ TrafficStatInfo trafficStatInfo = null;
+ ObjectNode tsJson = get(json, TRAFFIC_STATISTICS);
+ if (tsJson != null) {
+ JsonCodec<TrafficStatInfo> trafficStatInfoJsonCodec =
+ context.codec(TrafficStatInfo.class);
+ trafficStatInfo = trafficStatInfoJsonCodec.decode(tsJson, context);
+ }
+
+ final JsonCodec<ProtocolStatInfo> protocolStatInfoCodec =
+ context.codec(ProtocolStatInfo.class);
+
+ List<ProtocolStatInfo> detectedProtos = new ArrayList<>();
+ JsonNode dpJson = json.get(DETECTED_PROTOS);
+ if (dpJson != null) {
+ IntStream.range(0, dpJson.size())
+ .forEach(i -> detectedProtos.add(
+ protocolStatInfoCodec.decode(get(dpJson, i),
+ context)));
+ }
+
+ final JsonCodec<FlowStatInfo> flowStatInfoCodec =
+ context.codec(FlowStatInfo.class);
+
+ List<FlowStatInfo> knownFlows = new ArrayList<>();
+ JsonNode kfJson = json.get(KNOWN_FLOWS);
+ if (kfJson != null) {
+ IntStream.range(0, kfJson.size())
+ .forEach(i -> knownFlows.add(
+ flowStatInfoCodec.decode(get(kfJson, i),
+ context)));
+ }
+
+ List<FlowStatInfo> unknownFlows = new ArrayList<>();
+ JsonNode ufJson = json.get(UNKNOWN_FLOWS);
+ if (ufJson != null) {
+ IntStream.range(0, ufJson.size())
+ .forEach(i -> unknownFlows.add(
+ flowStatInfoCodec.decode(get(ufJson, i),
+ context)));
+ }
+
+ return new DpiStatInfo(trafficStatInfo,
+ detectedProtos,
+ knownFlows,
+ unknownFlows);
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java
new file mode 100644
index 0000000..e6bb618
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatistics.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * DPI statistics with received time.
+ */
+public class DpiStatistics {
+ private final String receivedTime;
+ private final DpiStatInfo dpiStatInfo;
+
+ /**
+ * Constructor for DpiStatistics class.
+ *
+ * @param receivedTime dpiStatInfo received time
+ * @param dpiStatInfo the dpi statistics info
+ */
+ public DpiStatistics(final String receivedTime, final DpiStatInfo dpiStatInfo) {
+ checkNotNull(receivedTime, "Must specify receivedTime");
+ checkNotNull(dpiStatInfo, "Must specify DpiStatInfo");
+
+ this.receivedTime = receivedTime;
+ this.dpiStatInfo = dpiStatInfo;
+ }
+
+ /**
+ * Returns DPI statistics received time.
+ *
+ * @return receivedTime
+ */
+ public String receivedTime() {
+ return receivedTime;
+ }
+
+ /**
+ * Returns DPI statistics information.
+ *
+ * @return dpiStatInfo
+ */
+ public DpiStatInfo dpiStatInfo() {
+ return dpiStatInfo;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(receivedTime, dpiStatInfo);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final DpiStatistics other = (DpiStatistics) obj;
+ if (!Objects.equals(this.receivedTime, other.receivedTime)) {
+ return false;
+ }
+ if (!Objects.equals(this.dpiStatInfo, other.dpiStatInfo)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("receivedTime", receivedTime)
+ .add("dpiStatInfo", dpiStatInfo)
+ .toString();
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java
new file mode 100644
index 0000000..c448277
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsCodec.java
@@ -0,0 +1,73 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for DpiStatistics codec.
+ */
+public final class DpiStatisticsCodec extends JsonCodec<DpiStatistics> {
+
+ private static final String RECEIVED_TIME = "receivedTime";
+ private static final String DPI_STATISTICS = "dpiStatistics";
+
+ private final Logger log = getLogger(getClass());
+
+ @Override
+ public ObjectNode encode(DpiStatistics ds, CodecContext context) {
+ checkNotNull(ds, "DpiStatistics cannot be null");
+
+ final ObjectNode result = context.mapper().createObjectNode();
+
+ result.put(RECEIVED_TIME, ds.receivedTime());
+
+ final JsonCodec<DpiStatInfo> dpiStatInfoCodec =
+ context.codec(DpiStatInfo.class);
+
+ final ObjectNode jsonDpiStatInfo = dpiStatInfoCodec.encode(ds.dpiStatInfo(), context);
+ result.set(DPI_STATISTICS, jsonDpiStatInfo);
+
+ return result;
+ }
+
+ @Override
+ public DpiStatistics decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ log.debug("receivedTime={}, full json={} ", json.get("receivedTime"), json);
+ JsonNode receivedTimeJson = json.get(RECEIVED_TIME);
+ String receivedTime = receivedTimeJson == null ? "" : receivedTimeJson.asText();
+
+ final JsonCodec<DpiStatInfo> dpiStatInfoCodec =
+ context.codec(DpiStatInfo.class);
+
+ DpiStatInfo dpiStatInfo =
+ dpiStatInfoCodec.decode(get(json, DPI_STATISTICS), context);
+
+ return new DpiStatistics(receivedTime, dpiStatInfo);
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java
new file mode 100644
index 0000000..5d03536
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/DpiStatisticsManagerService.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import java.util.List;
+
+/**
+ * Service for DPI Statistics Service Manager.
+ */
+public interface DpiStatisticsManagerService {
+ /**
+ * Get the latest DpiStatistics in the Store list.
+ *
+ * @return the DpiStatistics object class or null if not exist
+ */
+ DpiStatistics getDpiStatisticsLatest();
+
+ /**
+ * Get the latest DpiStatistics in the Store list.
+ *
+ * @param topnProtocols detected topn protocols, default = 100
+ * @param topnFlows detected topn known and unknown flows , default = 100
+ *
+ * @return the DpiStatistics object class or null if not exist
+ */
+ DpiStatistics getDpiStatisticsLatest(int topnProtocols, int topnFlows);
+
+ /**
+ * Gets the last N(Max = 100) DpiStatistics in the Store list.
+ *
+ * @param lastN maximum number to fetch
+ * @return the List of DpiStatistics object class
+ */
+ List<DpiStatistics> getDpiStatistics(int lastN);
+
+ /**
+ * Gets the last N(Max = 100) DpiStatistics in the Store list.
+ *
+ * @param lastN latest N entries
+ * @param topnProtocols detected topn protocols, default = 100
+ * @param topnFlows detected topn known and unknown flows , default = 100
+ * @return the List of DpiStatistics object class
+ */
+ List<DpiStatistics> getDpiStatistics(int lastN, int topnProtocols, int topnFlows);
+
+ /**
+ * Get the specified receivedTime DpiStatistics in the Store list.
+ *
+ * @param receivedTime receivedTime string with format "yyyy-MM-dd HH:mm:ss"
+ * @return the DpiStatistics object class or null if not exist
+ */
+ DpiStatistics getDpiStatistics(String receivedTime);
+
+ /**
+ * Get the specified receivedTime DpiStatistics in the Store list.
+ *
+ * @param receivedTime receivedTime string with format "yyyy-MM-dd HH:mm:ss"
+ * @param topnProtocols detected topn protocols, default = 100
+ * @param topnFlows detected topn known and unknown flows , default = 100
+ * @return the DpiStatistics object class or null if not exist
+ */
+ DpiStatistics getDpiStatistics(String receivedTime, int topnProtocols, int topnFlows);
+
+ /**
+ * Adds DpiStatistics at the end of the Store list.
+ *
+ * @param ds statistics to add
+ * @return the added DpiStatistics object class
+ */
+ DpiStatistics addDpiStatistics(DpiStatistics ds);
+
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java
new file mode 100644
index 0000000..bb409db
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfo.java
@@ -0,0 +1,251 @@
+/*
+ * 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;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Flow statistic information.
+ */
+public class FlowStatInfo {
+ String protocol;
+ String hostAName;
+ int hostAPort;
+ String hostBName;
+ int hostBPort;
+ int detectedProtocol;
+ String detectedProtocolName;
+ long packets;
+ long bytes;
+ String hostServerName;
+
+ /**
+ * Constructor for default FlowStatInfo class.
+ */
+ public FlowStatInfo() {
+ protocol = "";
+ hostAName = "::";
+ hostAPort = 0;
+ hostBName = "";
+ hostBPort = 0;
+ detectedProtocol = 0;
+ detectedProtocolName = "";
+ packets = 0;
+ bytes = 0;
+
+ hostServerName = "";
+ }
+
+ /**
+ * Constructor for FlowStatInfo class specified with flow statistic parameters.
+ *
+ * @param protocol protocol
+ * @param hostAName host A name
+ * @param hostAPort host A port
+ * @param hostBName host B name
+ * @param hostBPort host B port
+ * @param detectedProtocol detected protocol
+ * @param detectedProtocolName detected protocol name
+ * @param packets packet count
+ * @param bytes byte count
+ */
+ public FlowStatInfo(String protocol, String hostAName, int hostAPort, String hostBName, int hostBPort,
+ int detectedProtocol, String detectedProtocolName, long packets, long bytes) {
+ this.protocol = protocol;
+ this.hostAName = hostAName;
+ this.hostAPort = hostAPort;
+ this.hostBName = hostBName;
+ this.hostBPort = hostBPort;
+ this.detectedProtocol = detectedProtocol;
+ this.detectedProtocolName = detectedProtocolName;
+ this.packets = packets;
+ this.bytes = bytes;
+
+ hostServerName = "";
+ }
+
+ /**
+ * Constructor for FlowStatInfo class specified with flow statistic parameters and hostServerName.
+ *
+ * @param protocol protocol
+ * @param hostAName host A name
+ * @param hostAPort host A port
+ * @param hostBName host B name
+ * @param hostBPort host B port
+ * @param detectedProtocol detected protocol
+ * @param detectedProtocolName detected protocol name
+ * @param packets packet count
+ * @param bytes byte count
+ * @param hostServerName host server name
+ */
+ public FlowStatInfo(String protocol, String hostAName, int hostAPort, String hostBName, int hostBPort,
+ int detectedProtocol, String detectedProtocolName, long packets, long bytes,
+ String hostServerName) {
+ this(protocol, hostAName, hostAPort, hostBName, hostBPort, detectedProtocol, detectedProtocolName,
+ packets, bytes);
+
+ this.hostServerName = hostServerName;
+ }
+
+ /**
+ * Returns DPI flow protocol.
+ *
+ * @return protocol
+ */
+ public String protocol() {
+ return protocol;
+ }
+
+ /**
+ * Returns DPI flow host A name.
+ *
+ * @return hostAName
+ */
+ public String hostAName() {
+ return hostAName;
+ }
+
+ /**
+ * Returns DPI flow host A port.
+ *
+ * @return hostAPort
+ */
+ public int hostAPort() {
+ return hostAPort;
+ }
+
+
+ /**
+ * Returns DPI flow host B name.
+ *
+ * @return hostBName
+ */
+ public String hostBName() {
+ return hostBName;
+ }
+
+ /**
+ * Returns DPI flow host B Port.
+ *
+ * @return hostBPort
+ */
+ public int hostBPort() {
+ return hostBPort;
+ }
+
+ /**
+ * Returns DPI flow detected protocol.
+ *
+ * @return detectedProtocol
+ */
+ public int detectedProtocol() {
+ return detectedProtocol;
+ }
+
+ /**
+ * Returns DPI flow detected protocol name.
+ *
+ * @return detectedProtocolName
+ */
+ public String detectedProtocolName() {
+ return detectedProtocolName;
+ }
+
+ /**
+ * Returns DPI flow packets.
+ *
+ * @return packets
+ */
+ public long packets() {
+ return packets;
+ }
+
+ /**
+ * Returns DPI flow bytes.
+ *
+ * @return bytes
+ */
+ public long bytes() {
+ return bytes;
+ }
+
+ /**
+ * Returns DPI flow host server name.
+ *
+ * @return hostServerName
+ */
+ public String hostServerName() {
+ return hostServerName;
+ }
+
+
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ public void setHostAName(String hostAName) {
+ this.hostAName = hostAName;
+ }
+
+ public void setHostAPort(int hostAPort) {
+ this.hostAPort = hostAPort;
+ }
+
+ public void setHostBName(String hostBName) {
+ this.hostBName = hostBName;
+ }
+
+ public void setHostBPort(int hostBPort) {
+ this.hostBPort = hostBPort;
+ }
+
+ public void setDetectedProtocol(int detectedProtocol) {
+ this.detectedProtocol = detectedProtocol;
+ }
+
+ public void setDetectedProtocolName(String detectedProtocolName) {
+ this.detectedProtocolName = detectedProtocolName;
+ }
+
+ public void setPackets(long packets) {
+ this.packets = packets;
+ }
+
+ public void setBytes(long bytes) {
+ this.bytes = bytes;
+ }
+
+ public void setHostServerName(String hostServerName) {
+ this.hostServerName = hostServerName;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("protocol", protocol)
+ .add("hostAName", hostAName)
+ .add("hostAPort", hostAPort)
+ .add("hostBName", hostBName)
+ .add("hostBPort", hostBPort)
+ .add("detectedProtocol", detectedProtocol)
+ .add("detectedProtocolName", detectedProtocolName)
+ .add("packets", packets)
+ .add("bytes", bytes)
+ .add("hostServerName", hostServerName)
+ .toString();
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java
new file mode 100644
index 0000000..57a3bad
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/FlowStatInfoCodec.java
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for FlowStatInfo codec.
+ */
+public final class FlowStatInfoCodec extends JsonCodec<FlowStatInfo> {
+
+ private final Logger log = getLogger(getClass());
+
+ @Override
+ public ObjectNode encode(FlowStatInfo fsi, CodecContext context) {
+ checkNotNull(fsi, "FlowStatInfo cannot be null");
+
+ return context.mapper().createObjectNode()
+ .put("protocol", fsi.protocol())
+ .put("hostAName", fsi.hostAName())
+ .put("hostAPort", fsi.hostAPort())
+ .put("hostBName", fsi.hostBName())
+ .put("hostBPort", fsi.hostBPort())
+ .put("detectedProtocol", fsi.detectedProtocol())
+ .put("detectedProtocolName", fsi.detectedProtocolName())
+ .put("packets", fsi.packets())
+ .put("bytes", fsi.bytes())
+ .put("hostServerName", fsi.hostServerName());
+ }
+
+ @Override
+ public FlowStatInfo decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ log.debug("protocol={}, full json={} ", json.get("protocol"), json);
+ final String protocol = json.get("protocol").asText();
+ final String hostAName = json.get("hostAName").asText();
+ final int hostAPort = json.get("hostAPort").asInt();
+ final String hostBName = json.get("hostBName").asText();
+ final int hostBPort = json.get("hostBPort").asInt();
+ final int detectedProtocol = json.get("detectedProtocol").asInt();
+ final String detectedProtocolName = json.get("detectedProtocolName").asText();
+ final long packets = json.get("packets").asLong();
+ final long bytes = json.get("bytes").asLong();
+ final String hostServerName = json.get("hostServerName").asText();
+
+ return new FlowStatInfo(protocol,
+ hostAName, hostAPort, hostBName, hostBPort,
+ detectedProtocol, detectedProtocolName,
+ packets, bytes, hostServerName);
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java
new file mode 100644
index 0000000..22ac9a1
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfo.java
@@ -0,0 +1,135 @@
+/*
+ * 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;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Protocol statistic information.
+ */
+public class ProtocolStatInfo {
+ String name;
+ String breed;
+ long packets;
+ long bytes;
+ int flows;
+
+ /**
+ * Constructor for default ProtocolStatInfo class.
+ */
+ public ProtocolStatInfo() {
+ name = "";
+ breed = "";
+ packets = 0;
+ bytes = 0;
+ flows = 0;
+ }
+
+ /**
+ * Constructor for ProtocolStatInfo class specified with protocol statistic parameters.
+ *
+ * @param name protocol name
+ * @param breed protocol breed
+ * @param packets protocol packets
+ * @param bytes protocol bytes
+ * @param flows protocol flows
+ */
+ public ProtocolStatInfo(String name, String breed, long packets, long bytes, int flows) {
+ this.name = name;
+ this.breed = breed;
+ this.packets = packets;
+ this.bytes = bytes;
+ this.flows = flows;
+ }
+
+ /**
+ * Returns DPI protocol name.
+ *
+ * @return name
+ */
+ public String name() {
+ return name;
+ }
+
+ /**
+ * Returns DPI protocol breed.
+ *
+ * @return breed
+ */
+ public String breed() {
+ return breed;
+ }
+
+ /**
+ * Returns DPI protocol packets.
+ *
+ * @return packets
+ */
+ public long packets() {
+ return packets;
+ }
+
+ /**
+ * Returns DPI protocol bytes.
+ *
+ * @return bytes
+ */
+ public long bytes() {
+ return bytes;
+ }
+
+ /**
+ * Returns DPI protocol flows.
+ *
+ * @return flows
+ */
+ public int flows() {
+ return flows;
+ }
+
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setBreed(String breed) {
+ this.breed = breed;
+ }
+
+ public void setPackets(long packets) {
+ this.packets = packets;
+ }
+
+ public void setBytes(long bytes) {
+ this.bytes = bytes;
+ }
+
+ public void setFlows(int flows) {
+ this.flows = flows;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("name", name)
+ .add("breed", breed)
+ .add("packets", packets)
+ .add("bytes", bytes)
+ .add("flows", flows)
+ .toString();
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java
new file mode 100644
index 0000000..9469f6c
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/ProtocolStatInfoCodec.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for ProtocolStatInfo codec.
+ */
+public final class ProtocolStatInfoCodec extends JsonCodec<ProtocolStatInfo> {
+
+ private final Logger log = getLogger(getClass());
+
+ @Override
+ public ObjectNode encode(ProtocolStatInfo psi, CodecContext context) {
+ checkNotNull(psi, "ProtocolStatInfo cannot be null");
+
+ return context.mapper().createObjectNode()
+ .put("name", psi.name())
+ .put("breed", psi.breed())
+ .put("packets", psi.packets())
+ .put("bytes", psi.bytes())
+ .put("flows", psi.flows());
+ }
+
+ @Override
+ public ProtocolStatInfo decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ log.debug("name={}, full json={} ", json.get("name"), json);
+ final String name = json.get("name").asText();
+ final String breed = json.get("breed").asText();
+ final long packets = json.get("packets").asLong();
+ final long bytes = json.get("bytes").asLong();
+ final int flows = json.get("flows").asInt();
+
+ return new ProtocolStatInfo(name, breed, packets, bytes, flows);
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java
new file mode 100644
index 0000000..57cce19
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfo.java
@@ -0,0 +1,324 @@
+/*
+ * 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;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Traffic statistic information.
+ */
+public class TrafficStatInfo {
+ long ethernetBytes;
+ long discardedBytes;
+ long ipPackets;
+ long totalPackets;
+ long ipBytes;
+ int avgPktSize;
+ int uniqueFlows;
+ long tcpPackets;
+ long udpPackets;
+
+ double dpiThroughputPps;
+ double dpiThroughputBps;
+ double trafficThroughputPps;
+ double trafficThroughputBps;
+ double trafficDurationSec;
+ int guessedFlowProtos;
+
+ static final String PPS_STRING = "pps";
+ static final String BPS_STRING = "bps";
+ static final String SEC_STRING = "sec";
+
+ /**
+ * Constructor for default TrafficStatInfo class.
+ */
+ public TrafficStatInfo() {
+ ethernetBytes = 0;
+ discardedBytes = 0;
+ ipPackets = 0;
+ totalPackets = 0;
+ ipBytes = 0;
+ avgPktSize = 0;
+ uniqueFlows = 0;
+ tcpPackets = 0;
+ udpPackets = 0;
+ dpiThroughputPps = 0;
+ dpiThroughputBps = 0;
+ trafficThroughputPps = 0;
+ trafficThroughputBps = 0;
+ trafficDurationSec = 0;
+ guessedFlowProtos = 0;
+ }
+
+ /**
+ * Constructor for TrafficStatInfo class specified with traffic statistic parameters.
+ *
+ * @param ethernetBytes ethernet byte count
+ * @param discardedBytes discarded byte count
+ * @param ipPackets IP packet count
+ * @param totalPackets total packet count
+ * @param ipBytes total IP byte count
+ * @param avgPktSize average packet size
+ * @param uniqueFlows unique flows count
+ * @param tcpPackets TCP packet count
+ * @param udpPackets UDP packet count
+ * @param trafficThroughputPps traffic throughput PPS
+ * @param trafficThroughputBps traffic throughput BPS
+ * @param dpiThroughputPps DPI throughput PPS
+ * @param dpiThroughputBps DPI throughput BPS
+ * @param trafficDurationSec traffic duration in seconds
+ * @param guessedFlowProtos guess flow protocols
+ */
+ public TrafficStatInfo(long ethernetBytes, long discardedBytes, long ipPackets, long totalPackets,
+ long ipBytes, int avgPktSize, int uniqueFlows, long tcpPackets, long udpPackets,
+ double dpiThroughputPps, double dpiThroughputBps,
+ double trafficThroughputPps, double trafficThroughputBps,
+ double trafficDurationSec, int guessedFlowProtos) {
+ this.ethernetBytes = ethernetBytes;
+ this.discardedBytes = discardedBytes;
+ this.ipPackets = ipPackets;
+ this.totalPackets = totalPackets;
+ this.ipBytes = ipBytes;
+ this.avgPktSize = avgPktSize;
+ this.uniqueFlows = uniqueFlows;
+ this.tcpPackets = tcpPackets;
+ this.udpPackets = udpPackets;
+ this.dpiThroughputPps = dpiThroughputPps;
+ this.dpiThroughputBps = dpiThroughputBps;
+ this.trafficThroughputPps = trafficThroughputPps;
+ this.trafficThroughputBps = trafficThroughputBps;
+ this.trafficDurationSec = trafficDurationSec;
+ this.guessedFlowProtos = guessedFlowProtos;
+ }
+
+ /**
+ * Returns DPI traffic ethernet bytes.
+ *
+ * @return ethernetBytes
+ */
+ public long ethernetBytes() {
+ return ethernetBytes;
+ }
+
+ /**
+ * Returns DPI traffic discarded bytes.
+ *
+ * @return discardedBytes
+ */
+ public long discardedBytes() {
+ return discardedBytes;
+ }
+
+ /**
+ * Returns DPI traffic ip packets.
+ *
+ * @return ipPackets
+ */
+ public long ipPackets() {
+ return ipPackets;
+ }
+
+ /**
+ * Returns DPI traffic total packets.
+ *
+ * @return totalPackets
+ */
+ public long totalPackets() {
+ return totalPackets;
+ }
+
+ /**
+ * Returns DPI traffic ip bytes.
+ *
+ * @return ipBytes
+ */
+ public long ipBytes() {
+ return ipBytes;
+ }
+
+ /**
+ * Returns DPI traffic average packet size.
+ *
+ * @return avgPktSize
+ */
+ public int avgPktSize() {
+ return avgPktSize;
+ }
+
+ /**
+ * Returns DPI traffic the number of unique flows.
+ *
+ * @return uniqueFlows
+ */
+ public int uniqueFlows() {
+ return uniqueFlows;
+ }
+
+ /**
+ * Returns DPI traffic TCP packets.
+ *
+ * @return tcpPackets
+ */
+ public long tcpPackets() {
+ return tcpPackets;
+ }
+
+ /**
+ * Returns DPI traffic UDP packets.
+ *
+ * @return udpPackets
+ */
+ public long udpPackets() {
+ return udpPackets;
+ }
+
+ /**
+ * Returns DPI traffic throughput Pps(Packet per second).
+ *
+ * @return dpiThroughputPps
+ */
+ public double dpiThroughputPps() {
+ return dpiThroughputPps;
+ }
+
+ /**
+ * Returns DPI traffic throughput Bps(Byte per second).
+ *
+ * @return dpiThroughputBps
+ */
+ public double dpiThroughputBps() {
+ return dpiThroughputBps;
+ }
+
+ /**
+ * Returns total traffic throughput Pps(Packet per second).
+ *
+ * @return trafficThroughputPps
+ */
+ public double trafficThroughputPps() {
+ return trafficThroughputPps;
+ }
+
+ /**
+ * Returns total traffic throughput Bps(Byte per second).
+ *
+ * @return trafficThroughputBps
+ */
+ public double trafficThroughputBps() {
+ return trafficThroughputBps;
+ }
+
+ /**
+ * Returns DPI traffic duration second.
+ *
+ * @return trafficDurationSec
+ */
+ public double trafficDurationSec() {
+ return trafficDurationSec;
+ }
+
+ /**
+ * Returns DPI traffic the number of guessed flow protocols.
+ *
+ * @return guessedFlowProtos
+ */
+ public int guessedFlowProtos() {
+ return guessedFlowProtos;
+ }
+
+
+ public void setEthernetBytes(long ethernetBytes) {
+ this.ethernetBytes = ethernetBytes;
+ }
+
+ public void setDiscardedBytes(long discardedBytes) {
+ this.discardedBytes = discardedBytes;
+ }
+
+ public void setIpPackets(long ipPackets) {
+ this.ipPackets = ipPackets;
+ }
+
+ public void setTotalPackets(long totalPackets) {
+ this.totalPackets = totalPackets;
+ }
+
+ public void setIpBytes(long ipBytes) {
+ this.ipBytes = ipBytes;
+ }
+
+ public void setAvgPktSize(int avgPktSize) {
+ this.avgPktSize = avgPktSize;
+ }
+
+ public void setUniqueFlows(int uniqueFlows) {
+ this.uniqueFlows = uniqueFlows;
+ }
+
+ public void setTcpPackets(long tcpPackets) {
+ this.tcpPackets = tcpPackets;
+ }
+
+ public void setUdpPackets(long udpPackets) {
+ this.udpPackets = udpPackets;
+ }
+
+ public void setDpiThroughputPps(double dpiThroughputPps) {
+ this.dpiThroughputPps = dpiThroughputPps;
+ }
+
+ public void setDpiThroughputBps(double dpiThroughputBps) {
+ this.dpiThroughputBps = dpiThroughputBps;
+ }
+
+ public void setTrafficThroughputPps(double trafficThroughputPps) {
+ this.trafficThroughputPps = trafficThroughputPps;
+ }
+
+ public void setTrafficThroughputBps(double trafficThroughputBps) {
+ this.trafficThroughputBps = trafficThroughputBps;
+ }
+
+ public void setTrafficDurationSec(double trafficDurationSec) {
+ this.trafficDurationSec = trafficDurationSec;
+ }
+
+ public void setGuessedFlowProtos(int guessedFlowProtos) {
+ this.guessedFlowProtos = guessedFlowProtos;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("ethernetBytes", ethernetBytes)
+ .add("discardedBytes", discardedBytes)
+ .add("ipPackets", ipPackets)
+ .add("totalPackets", totalPackets)
+ .add("ipBytes", ipBytes)
+ .add("avgPktSize", avgPktSize)
+ .add("uniqueFlows", uniqueFlows)
+ .add("tcpPackets", tcpPackets)
+ .add("udpPackets", udpPackets)
+ .add("dpiThroughputPps", dpiThroughputPps + " " + PPS_STRING)
+ .add("dpiThroughputBps", dpiThroughputBps + " " + BPS_STRING)
+ .add("trafficThroughputPps", trafficThroughputPps + " " + PPS_STRING)
+ .add("trafficThroughputBps", trafficThroughputBps + " " + BPS_STRING)
+ .add("trafficDurationSec", trafficDurationSec + " " + SEC_STRING)
+ .add("guessedFlowProtos", guessedFlowProtos)
+ .toString();
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java
new file mode 100644
index 0000000..dafe523
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/TrafficStatInfoCodec.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Implementation of encoder for TrafficStatInfo codec.
+ */
+public final class TrafficStatInfoCodec extends JsonCodec<TrafficStatInfo> {
+
+ private final Logger log = getLogger(getClass());
+
+ @Override
+ public ObjectNode encode(TrafficStatInfo tsi, CodecContext context) {
+ checkNotNull(tsi, "TrafficStatInfo cannot be null");
+
+ return context.mapper().createObjectNode()
+ .put("ethernetBytes", tsi.ethernetBytes())
+ .put("discardedBytes", tsi.discardedBytes())
+ .put("ipPackets", tsi.ipPackets())
+ .put("totalPackets", tsi.totalPackets())
+ .put("ipBytes", tsi.ipBytes())
+ .put("avgPktSize", tsi.avgPktSize())
+ .put("uniqueFlows", tsi.uniqueFlows())
+ .put("tcpPackets", tsi.tcpPackets())
+ .put("udpPackets", tsi.udpPackets())
+ .put("dpiThroughputPps", tsi.dpiThroughputPps())
+ .put("dpiThroughputBps", tsi.dpiThroughputBps())
+ .put("trafficThroughputPps", tsi.trafficThroughputPps())
+ .put("trafficThroughputBps", tsi.trafficThroughputBps())
+ .put("trafficDurationSec", tsi.trafficDurationSec())
+ .put("guessedFlowProtos", tsi.guessedFlowProtos());
+ }
+
+ @Override
+ public TrafficStatInfo decode(ObjectNode json, CodecContext context) {
+ if (json == null || !json.isObject()) {
+ return null;
+ }
+
+ log.debug("ethernetBytes={}, full json={} ", json.get("ethernetBytes"), json);
+ final Long ethernetBytes = json.get("ethernetBytes").asLong();
+ final Long discardedBytes = json.get("discardedBytes").asLong();
+ final Long ipPackets = json.get("ipPackets").asLong();
+ final Long totalPackets = json.get("totalPackets").asLong();
+ final Long ipBytes = json.get("ipBytes").asLong();
+ final int avgPktSize = json.get("avgPktSize").asInt();
+ final int uniqueFlows = json.get("uniqueFlows").asInt();
+ final Long tcpPackets = json.get("tcpPackets").asLong();
+ final Long udpPackets = json.get("udpPackets").asLong();
+ final double dpiThroughputPps = json.get("dpiThroughputPps").asDouble();
+ final double dpiThroughputBps = json.get("dpiThroughputBps").asDouble();
+ final double trafficThroughputPps = json.get("trafficThroughputPps").asDouble();
+ final double trafficThroughputBps = json.get("trafficThroughputBps").asDouble();
+ final double trafficDurationSec = json.get("trafficDurationSec").asDouble();
+ final int guessedFlowProtos = json.get("guessedFlowProtos").asInt();
+
+ return new TrafficStatInfo(ethernetBytes,
+ discardedBytes,
+ ipPackets, totalPackets,
+ ipBytes, avgPktSize,
+ uniqueFlows,
+ tcpPackets, udpPackets,
+ dpiThroughputPps, dpiThroughputBps,
+ trafficThroughputPps, trafficThroughputBps,
+ trafficDurationSec,
+ guessedFlowProtos);
+ }
+}
diff --git a/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/package-info.java
new file mode 100644
index 0000000..3f769b8
--- /dev/null
+++ b/apps/dpistats/api/src/main/java/org/onosproject/incubator/net/dpi/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.
+ */
+
+/**
+ * Subsystem for dpi statistics service.
+ */
+package org.onosproject.incubator.net.dpi;
\ No newline at end of file
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"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}