/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.rest.resources; 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.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 = (ObjectNode) mapper().readTree(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(); } }