Detangling incubator: virtual nets, tunnels, resource labels, oh my
- virtual networking moved to /apps/virtual; with CLI & REST API
- tunnels and labels moved to /apps/tunnel; with CLI & REST API; UI disabled for now
- protobuf/models moved to /core/protobuf/models
- defunct grpc/rpc registry stuff left under /graveyard
- compile dependencies on /incubator moved to respective modules for compilation
- run-time dependencies will need to be re-tested for dependent apps
- /graveyard will be removed in not-too-distant future
Change-Id: I0a0b995c635487edcf95a352f50dd162186b0b39
diff --git a/apps/dpistats/app/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);
+ }
+ }
+}