From a4eac6a3b2c3b85585956fda583e6965c8522ada Mon Sep 17 00:00:00 2001 From: Thomas Vachuska Date: Mon, 1 Mar 2021 15:11:59 -0800 Subject: [PATCH] [AETHER-1211] Allowing toggling of link labels via Alt-L Change-Id: I772b6ee0c6c24eeb48466a96a45b44b9ee6eef50 --- .../provider/nil/NullProviders.java | 2 + .../provider/nil/PortStatsDriver.java | 101 ++++++++++++++++++ web/gui/src/main/webapp/app/view/topo/topo.js | 1 + .../src/main/webapp/app/view/topo/topoD3.js | 73 ++++++++----- .../main/webapp/app/view/topo/topoForce.js | 5 + 5 files changed, 154 insertions(+), 28 deletions(-) create mode 100644 providers/null/src/main/java/org/onosproject/provider/nil/PortStatsDriver.java diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java index d95943b4d8..ed870f491a 100644 --- a/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java +++ b/providers/null/src/main/java/org/onosproject/provider/nil/NullProviders.java @@ -135,6 +135,7 @@ public class NullProviders { private final NullGroupProvider groupProvider = new NullGroupProvider(); private final NullPacketProvider packetProvider = new NullPacketProvider(); private final TopologyMutationDriver topologyMutationDriver = new TopologyMutationDriver(); + private final PortStatsDriver portStatsDriver = new PortStatsDriver(); private DeviceProviderService deviceProviderService; private HostProviderService hostProviderService; @@ -349,6 +350,7 @@ public class NullProviders { topologyMutationDriver.start(mutationRate, linkService, deviceService, linkProviderService, deviceProviderService, simulator); + portStatsDriver.start(deviceService, deviceProviderService); } // Selects the simulator based on the specified name. diff --git a/providers/null/src/main/java/org/onosproject/provider/nil/PortStatsDriver.java b/providers/null/src/main/java/org/onosproject/provider/nil/PortStatsDriver.java new file mode 100644 index 0000000000..8ad269ce3c --- /dev/null +++ b/providers/null/src/main/java/org/onosproject/provider/nil/PortStatsDriver.java @@ -0,0 +1,101 @@ +/* + * Copyright 2015-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.provider.nil; + +import org.onosproject.net.Device; +import org.onosproject.net.Port; +import org.onosproject.net.device.DefaultPortStatistics; +import org.onosproject.net.device.DeviceProviderService; +import org.onosproject.net.device.DeviceService; +import org.onosproject.net.device.PortStatistics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.security.SecureRandom; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor; +import static org.onlab.util.Tools.delay; +import static org.onlab.util.Tools.groupedThreads; + +/** + * Drives port statistics simulation using random generator. + */ +class PortStatsDriver implements Runnable { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + private static final int WAIT_DELAY = 2_000; + + private final Random random = new SecureRandom(); + + private volatile boolean stopped = true; + + private DeviceService deviceService; + private DeviceProviderService deviceProviderService; + + private final ExecutorService executor = + newSingleThreadScheduledExecutor(groupedThreads("onos/null", "port-stats-mutator", log)); + + /** + * Starts the mutation process. + * + * @param deviceService device service + * @param deviceProviderService device provider service + */ + void start(DeviceService deviceService, + DeviceProviderService deviceProviderService) { + stopped = false; + this.deviceService = deviceService; + this.deviceProviderService = deviceProviderService; + executor.execute(this); + } + + /** + * Stops the mutation process. + */ + void stop() { + stopped = true; + } + + @Override + public void run() { + while (!stopped) { + delay(WAIT_DELAY); + deviceService.getAvailableDevices().forEach(this::updatePorts); + } + } + + public void updatePorts(Device device) { + Set portStats = new HashSet<>(); + for (Port port : deviceService.getPorts(device.id())) { + portStats.add(DefaultPortStatistics.builder() + .setBytesReceived(Math.abs(random.nextInt())) + .setBytesSent(Math.abs(random.nextInt())) + .setPacketsReceived(Math.abs(random.nextInt())) + .setPacketsSent(Math.abs(random.nextInt())) + .setDurationSec(2) + .setDeviceId(device.id()) + .setPort(port.number()) + .build()); + } + deviceProviderService.updatePortStatistics(device.id(), portStats); + } + +} diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js index 1348eec2be..4c87f86aea 100644 --- a/web/gui/src/main/webapp/app/view/topo/topo.js +++ b/web/gui/src/main/webapp/app/view/topo/topo.js @@ -104,6 +104,7 @@ N: [fltr.clickAction, cycLayer], L: [tfs.cycleDeviceLabels, cycDev], 'shift-L': [tfs.cycleHostLabels, cycHost], + 'alt-L': [tfs.cycleLinkLabels, quiet], U: [tfs.unpin, unpin], R: [resetZoom, rzoom], diff --git a/web/gui/src/main/webapp/app/view/topo/topoD3.js b/web/gui/src/main/webapp/app/view/topo/topoD3.js index 1b73fbf2ed..d89efd7e0c 100644 --- a/web/gui/src/main/webapp/app/view/topo/topoD3.js +++ b/web/gui/src/main/webapp/app/view/topo/topoD3.js @@ -101,7 +101,8 @@ // internal state var deviceLabelIndex = 0, - hostLabelIndex = 0; + hostLabelIndex = 0, + linkLabelsEnabled = true; // note: these are the device icon colors without affinity (no master) var dColTheme = { @@ -173,6 +174,11 @@ return d.labels[idx]; } + function toggleLinkLabels() { + linkLabelsEnabled = !linkLabelsEnabled; + return linkLabelsEnabled; + } + function trimLabel(label) { return (label && label.trim()) || ''; } @@ -390,39 +396,49 @@ var entering; api.updateLinkLabelModel(); + if (linkLabelsEnabled) { - // for elements already existing, we need to update the text - // and adjust the rectangle size to fit - api.linkLabel().each(function (d) { - var el = d3.select(this), - rect = el.select('rect'), - text = el.select('text'); - text.text(d.label); - rect.attr(rectAroundText(el)); - }); + // for elements already existing, we need to update the text + // and adjust the rectangle size to fit + api.linkLabel().each(function (d) { + var el = d3.select(this), + rect = el.select('rect'), + text = el.select('text'); + text.text(d.label); + rect.attr(rectAroundText(el)); + }); - entering = api.linkLabel().enter().append('g') - .classed('linkLabel', true) - .attr('id', function (d) { return d.id; }); + entering = api.linkLabel().enter().append('g') + .classed('linkLabel', true) + .attr('id', function (d) { return d.id; }); - entering.each(function (d) { - var el = d3.select(this), - rect, - text; + entering.each(function (d) { + var el = d3.select(this), + rect, + text; - if (d.ldata.type() === 'hostLink') { - el.classed('hostLinkLabel', true); - sus.visible(el, api.showHosts()); - } + if (d.ldata.type() === 'hostLink') { + el.classed('hostLinkLabel', true); + sus.visible(el, api.showHosts()); + } - d.el = el; - rect = el.append('rect'); - text = el.append('text').text(d.label); - rect.attr(rectAroundText(el)); - text.attr('dy', linkLabelOffset); + d.el = el; + rect = el.append('rect'); + text = el.append('text').text(d.label); + rect.attr(rectAroundText(el)); + text.attr('dy', linkLabelOffset); - el.attr('transform', transformLabel(d.ldata.position, d.key)); - }); + el.attr('transform', transformLabel(d.ldata.position, d.key)); + }); + } else { + api.linkLabel().each(function (d) { + var el = d3.select(this), + rect = el.select('rect'), + text = el.select('text'); + text.text(''); + rect.attr(rectAroundText(el)); + }); + } // Remove any labels that are no longer required. api.linkLabel().exit().remove(); @@ -648,6 +664,7 @@ setHostLabIndex: setHostLabIndex, hostLabel: hostLabel, deviceLabel: deviceLabel, + toggleLinkLabels: toggleLinkLabels, trimLabel: trimLabel, updateDeviceLabel: updateDeviceRendering, diff --git a/web/gui/src/main/webapp/app/view/topo/topoForce.js b/web/gui/src/main/webapp/app/view/topo/topoForce.js index e648d6d28b..dacbda91e8 100644 --- a/web/gui/src/main/webapp/app/view/topo/topoForce.js +++ b/web/gui/src/main/webapp/app/view/topo/topoForce.js @@ -551,6 +551,10 @@ }); } + function cycleLinkLabels() { + td3.toggleLinkLabels(); + } + function unpin() { var hov = tss.hovered(); if (hov) { @@ -1303,6 +1307,7 @@ toggleOffline: toggleOffline, cycleDeviceLabels: cycleDeviceLabels, cycleHostLabels: cycleHostLabels, + cycleLinkLabels: cycleLinkLabels, unpin: unpin, showMastership: showMastership, showBadLinks: showBadLinks,