ONOS-6259: Topo2 - Implement server-side highlighting model
- (Still WIP)
- refactored trafficSummary() and related methods up into superclass
- introduced hook method for link aggregation
Change-Id: I0a993bbc5ba5f0e861214f8d06877dad3f7bc8ee
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java
index dfedaf3..c59f2c5 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitorBase.java
@@ -17,15 +17,27 @@
package org.onosproject.ui.impl;
+import org.onosproject.incubator.net.PortStatisticsService.MetricType;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.statistic.Load;
import org.onosproject.ui.impl.topo.util.ServicesBundle;
+import org.onosproject.ui.impl.topo.util.TrafficLink;
+import org.onosproject.ui.impl.topo.util.TrafficLinkMap;
import org.onosproject.ui.topo.AbstractTopoMonitor;
+import org.onosproject.ui.topo.Highlights;
import org.onosproject.ui.topo.TopoUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.HashSet;
+import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
+import static org.onosproject.incubator.net.PortStatisticsService.MetricType.BYTES;
+import static org.onosproject.incubator.net.PortStatisticsService.MetricType.PACKETS;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.IDLE;
/**
@@ -36,7 +48,7 @@
private final Logger log = LoggerFactory.getLogger(getClass());
// 4 Kilo Bytes as threshold
- static final double BPS_THRESHOLD = 4 * TopoUtils.N_KILO;
+ protected static final double BPS_THRESHOLD = 4 * TopoUtils.N_KILO;
/**
@@ -221,6 +233,163 @@
// =======================================================================
+ // === Methods for computing traffic on links
+
+ /**
+ * Generates a {@link Highlights} object summarizing the traffic on the
+ * network, ready to be transmitted back to the client for display on
+ * the topology view.
+ *
+ * @param type the type of statistics to be displayed
+ * @return highlights, representing links to be labeled/colored
+ */
+ protected Highlights trafficSummary(TrafficLink.StatsType type) {
+ Highlights highlights = new Highlights();
+
+ // TODO: consider whether a map would be better...
+ Set<TrafficLink> linksWithTraffic = computeLinksWithTraffic(type);
+
+ Set<TrafficLink> aggregatedLinks = doAggregation(linksWithTraffic);
+
+ for (TrafficLink tlink : aggregatedLinks) {
+ highlights.add(tlink.highlight(type));
+ }
+ return highlights;
+ }
+
+ /**
+ * Generates a set of "traffic links" encapsulating information about the
+ * traffic on each link (that is deemed to have traffic).
+ *
+ * @param type the type of statistics to be displayed
+ * @return the set of links with traffic
+ */
+ protected Set<TrafficLink> computeLinksWithTraffic(TrafficLink.StatsType type) {
+ TrafficLinkMap linkMap = new TrafficLinkMap();
+ compileLinks(linkMap);
+ addEdgeLinks(linkMap);
+
+ Set<TrafficLink> linksWithTraffic = new HashSet<>();
+ // TODO: consider whether a map would be better...
+
+ for (TrafficLink tlink : linkMap.biLinks()) {
+ if (type == TrafficLink.StatsType.FLOW_STATS) {
+ attachFlowLoad(tlink);
+ } else if (type == TrafficLink.StatsType.PORT_STATS) {
+ attachPortLoad(tlink, BYTES);
+ } else if (type == TrafficLink.StatsType.PORT_PACKET_STATS) {
+ attachPortLoad(tlink, PACKETS);
+ }
+
+ // we only want to report on links deemed to have traffic
+ if (tlink.hasTraffic()) {
+ linksWithTraffic.add(tlink);
+ }
+ }
+ return linksWithTraffic;
+ }
+
+ /**
+ * Iterates across the set of links in the topology and generates the
+ * appropriate set of traffic links.
+ *
+ * @param linkMap link map to augment with traffic links
+ */
+ protected void compileLinks(TrafficLinkMap linkMap) {
+ services.link().getLinks().forEach(linkMap::add);
+ }
+
+ /**
+ * Iterates across the set of hosts in the topology and generates the
+ * appropriate set of traffic links for the edge links.
+ *
+ * @param linkMap link map to augment with traffic links
+ */
+ protected void addEdgeLinks(TrafficLinkMap linkMap) {
+ services.host().getHosts().forEach(host -> {
+ linkMap.add(createEdgeLink(host, true));
+ linkMap.add(createEdgeLink(host, false));
+ });
+ }
+
+ /**
+ * Processes the given traffic link to attach the "flow load" attributed
+ * to the underlying topology links.
+ *
+ * @param link the traffic link to process
+ */
+ protected void attachFlowLoad(TrafficLink link) {
+ link.addLoad(getLinkFlowLoad(link.one()));
+ link.addLoad(getLinkFlowLoad(link.two()));
+ }
+
+ /**
+ * Returns the load for the given link, as determined by the statistics
+ * service. May return null.
+ *
+ * @param link the link on which to look up the stats
+ * @return the corresponding load (or null)
+ */
+ protected Load getLinkFlowLoad(Link link) {
+ if (link != null && link.src().elementId() instanceof DeviceId) {
+ return services.flowStats().load(link);
+ }
+ return null;
+ }
+
+ /**
+ * Processes the given traffic link to attach the "port load" attributed
+ * to the underlying topology links, for the specified metric type (either
+ * bytes/sec or packets/sec).
+ *
+ * @param link the traffic link to process
+ * @param metricType the metric type (bytes or packets)
+ */
+ protected void attachPortLoad(TrafficLink link, MetricType metricType) {
+ // For bi-directional traffic links, use
+ // the max link rate of either direction
+ // (we choose 'one' since we know that is never null)
+ Link one = link.one();
+ Load egressSrc = services.portStats().load(one.src(), metricType);
+ Load egressDst = services.portStats().load(one.dst(), metricType);
+ link.addLoad(maxLoad(egressSrc, egressDst), metricType == BYTES ? BPS_THRESHOLD : 0);
+ }
+
+ /**
+ * Returns the load with the greatest rate.
+ *
+ * @param a load a
+ * @param b load b
+ * @return the larger of the two
+ */
+ protected Load maxLoad(Load a, Load b) {
+ if (a == null) {
+ return b;
+ }
+ if (b == null) {
+ return a;
+ }
+ return a.rate() > b.rate() ? a : b;
+ }
+
+
+ /**
+ * Subclasses (well, Traffic2Monitor really) can override this method and
+ * process the traffic links before generating the highlights object.
+ * In particular, links that roll up into "synthetic links" between
+ * regions should show aggregated data from the constituent links.
+ * <p>
+ * This default implementation does nothing.
+ *
+ * @param linksWithTraffic link data for all links
+ * @return transformed link data appropriate to the region display
+ */
+ protected Set<TrafficLink> doAggregation(Set<TrafficLink> linksWithTraffic) {
+ return linksWithTraffic;
+ }
+
+
+ // =======================================================================
// === Background Task
// Provides periodic update of traffic information to the client
@@ -258,5 +427,4 @@
}
}
}
-
}