| /* |
| * Copyright 2017-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.linkprops; |
| |
| import com.fasterxml.jackson.databind.node.ObjectNode; |
| import com.google.common.base.Strings; |
| import com.google.common.collect.ImmutableSet; |
| import org.onlab.osgi.ServiceDirectory; |
| import org.onlab.util.Bandwidth; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.Element; |
| import org.onosproject.net.HostId; |
| import org.onosproject.net.Link; |
| import org.onosproject.net.PortNumber; |
| import org.onosproject.net.device.DeviceService; |
| import org.onosproject.net.host.HostService; |
| import org.onosproject.net.link.LinkService; |
| import org.onosproject.net.resource.ContinuousResource; |
| import org.onosproject.ui.RequestHandler; |
| import org.onosproject.ui.UiConnection; |
| import org.onosproject.ui.UiMessageHandler; |
| import org.onosproject.ui.topo.Highlights; |
| import org.onosproject.ui.topo.TopoJson; |
| import org.onosproject.net.resource.DiscreteResourceId; |
| import org.onosproject.net.resource.Resources; |
| import org.onosproject.net.resource.ResourceQueryService; |
| import org.onosproject.incubator.net.PortStatisticsService; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.Collection; |
| import java.util.Set; |
| |
| /** |
| * ONOS UI Topology overlay for LinkProps. Creates the highlights for each link |
| * depending on the selected mode (rate,byte,band) and adds labels to egress |
| * links of the device being hovered over. |
| */ |
| public class LinkPropsTopovMessageHandler extends UiMessageHandler { |
| |
| private static final String LP_TOPOV_DISPLAY_START = "linkPropsTopovDisplayStart"; |
| private static final String LP_TOPOV_DISPLAY_UPDATE = "linkPropsTopovDisplayUpdate"; |
| private static final String LP_TOPOV_DISPLAY_STOP = "linkPropsTopovDisplayStop"; |
| |
| private static final String ID = "id"; |
| private static final String MODE = "mode"; |
| |
| private enum Mode { IDLE, RATE, BYTE, BAND } |
| |
| private final Logger log = LoggerFactory.getLogger(getClass()); |
| |
| private DeviceService deviceService; |
| private HostService hostService; |
| private LinkService linkService; |
| private PortStatisticsService portStatisticsService; |
| private ResourceQueryService resourceQueryService; |
| |
| private Mode currentMode = Mode.IDLE; |
| private Element elementOfNote; |
| |
| |
| // ===============-=-=-=-=-=-======================-=-=-=-=-=-=-================================ |
| |
| |
| @Override |
| public void init(UiConnection connection, ServiceDirectory directory) { |
| super.init(connection, directory); |
| deviceService = directory.get(DeviceService.class); |
| hostService = directory.get(HostService.class); |
| linkService = directory.get(LinkService.class); |
| portStatisticsService = directory.get(PortStatisticsService.class); |
| resourceQueryService = directory.get(ResourceQueryService.class); |
| } |
| |
| @Override |
| protected Collection<RequestHandler> createRequestHandlers() { |
| return ImmutableSet.of( |
| new DisplayStartHandler(), |
| new DisplayUpdateHandler(), |
| new DisplayStopHandler() |
| ); |
| } |
| |
| // === ------------------------- |
| // === Handler classes |
| |
| private final class DisplayStartHandler extends RequestHandler { |
| public DisplayStartHandler() { |
| super(LP_TOPOV_DISPLAY_START); |
| } |
| |
| @Override |
| public void process(ObjectNode payload) { |
| String mode = string(payload, MODE); |
| |
| log.debug("Start Display: mode [{}]", mode); |
| clearState(); |
| clearForMode(); |
| |
| switch (mode) { |
| case "rate": |
| currentMode = Mode.RATE; |
| sendRateData(); |
| break; |
| |
| case "byte": |
| currentMode = Mode.BYTE; |
| sendByteData(); |
| break; |
| |
| case "band": |
| currentMode = Mode.BAND; |
| sendBandwidth(); |
| break; |
| |
| default: |
| currentMode = Mode.IDLE; |
| break; |
| } |
| } |
| } |
| |
| private final class DisplayUpdateHandler extends RequestHandler { |
| public DisplayUpdateHandler() { |
| super(LP_TOPOV_DISPLAY_UPDATE); |
| } |
| |
| @Override |
| public void process(ObjectNode payload) { |
| String id = string(payload, ID); |
| log.debug("Update Display: id [{}]", id); |
| if (!Strings.isNullOrEmpty(id)) { |
| updateForMode(id); |
| } else { |
| clearForMode(); |
| } |
| } |
| } |
| |
| private final class DisplayStopHandler extends RequestHandler { |
| public DisplayStopHandler() { |
| super(LP_TOPOV_DISPLAY_STOP); |
| } |
| |
| @Override |
| public void process(ObjectNode payload) { |
| log.debug("Stop Display"); |
| clearState(); |
| clearForMode(); |
| } |
| } |
| |
| // === ------------ |
| |
| private void clearState() { |
| currentMode = Mode.IDLE; |
| elementOfNote = null; |
| } |
| |
| private void updateForMode(String id) { |
| log.debug("host service: {}", hostService); |
| log.debug("device service: {}", deviceService); |
| |
| try { |
| HostId hid = HostId.hostId(id); |
| log.debug("host id {}", hid); |
| elementOfNote = hostService.getHost(hid); |
| log.debug("host element {}", elementOfNote); |
| |
| } catch (Exception e) { |
| try { |
| DeviceId did = DeviceId.deviceId(id); |
| log.debug("device id {}", did); |
| elementOfNote = deviceService.getDevice(did); |
| log.debug("device element {}", elementOfNote); |
| |
| } catch (Exception e2) { |
| log.debug("Unable to process ID [{}]", id); |
| elementOfNote = null; |
| } |
| } |
| |
| switch (currentMode) { |
| case RATE: |
| sendRateData(); |
| break; |
| |
| case BYTE: |
| sendByteData(); |
| break; |
| |
| case BAND: |
| sendBandwidth(); |
| break; |
| |
| default: |
| break; |
| } |
| |
| } |
| |
| private void clearForMode() { |
| sendHighlights(new Highlights()); |
| } |
| |
| private void sendHighlights(Highlights highlights) { |
| sendMessage(TopoJson.highlightsMessage(highlights)); |
| } |
| |
| |
| private void sendRateData() { |
| if (elementOfNote != null && elementOfNote instanceof Device) { |
| DeviceId devId = (DeviceId) elementOfNote.id(); |
| Set<Link> links = linkService.getDeviceEgressLinks(devId); |
| Highlights highlights = getLinkSpeed(links, devId); |
| sendHighlights(highlights); |
| } |
| } |
| |
| private void sendBandwidth() { |
| if (elementOfNote != null && elementOfNote instanceof Device) { |
| DeviceId devId = (DeviceId) elementOfNote.id(); |
| Set<Link> links = linkService.getDeviceEgressLinks(devId); |
| Highlights highlights = getBandwidth(links, devId); |
| sendHighlights(highlights); |
| } |
| } |
| |
| /** |
| * Gets the links connected to the highlighted device. |
| * Creates a ContinuousResource object for each link |
| * and gets the bandwidth of the link from the query |
| * and sets the label of the link as the bandwidth value. |
| */ |
| private Highlights getBandwidth(Set<Link> links, DeviceId devId) { |
| LpLinkMap linkMap = new LpLinkMap(); |
| Highlights highlights = new Highlights(); |
| if (links != null) { |
| log.debug("Processing {} links", links.size()); |
| links.forEach(linkMap::add); |
| |
| PortNumber portnum = PortNumber.portNumber((int) links.iterator().next().src().port().toLong()); |
| |
| for (LpLink dlink : linkMap.biLinks()) { |
| DiscreteResourceId parent = Resources.discrete(devId, portnum).id(); |
| ContinuousResource continuousResource = |
| (ContinuousResource) resourceQueryService.getAvailableResources(parent, |
| Bandwidth.class).iterator().next(); |
| double availBandwidth = continuousResource.value(); |
| |
| dlink.makeImportant().setLabel(Double.toString(availBandwidth) + " bytes/s"); |
| highlights.add(dlink.highlight(null)); |
| } |
| } else { |
| log.debug("No egress links found for device {}", devId); |
| } |
| return highlights; |
| } |
| |
| /** |
| * Gets the links connected to the highlighted device. |
| * Uses PortStatisticsService to get a load object of |
| * the links and find the rate of data flow out of the |
| * device via that link (src) and into the device via |
| * that link (dst), because dlink.two() gives a |
| * NullPointerException. Creates a label which displays |
| * the src and dst rates for the link. |
| */ |
| private Highlights getLinkSpeed(Set<Link> links, DeviceId devId) { |
| LpLinkMap linkMap = new LpLinkMap(); |
| if (links != null) { |
| log.debug("Processing {} links", links.size()); |
| links.forEach(linkMap::add); |
| } else { |
| log.debug("No egress links found for device {}", devId); |
| } |
| |
| Highlights highlights = new Highlights(); |
| |
| for (LpLink dlink : linkMap.biLinks()) { |
| String rate = "Out: " + getSpeedString((portStatisticsService.load(dlink.one().src()).rate())) + " | In: " |
| + getSpeedString((portStatisticsService.load(dlink.one().dst()).rate())); |
| dlink.makeImportant().setLabel(rate); |
| highlights.add(dlink.highlight(null)); |
| } |
| return highlights; |
| } |
| |
| private String getSpeedString(Long speed) { |
| if (speed > 1_000_000_000) { |
| return Long.toString(speed / 1_000_000_000) + "Gb/s"; |
| } else if (speed > 1_000_000) { |
| return Long.toString(speed / 1_000_000) + "Mb/s"; |
| } else if (speed > 1_000) { |
| return Long.toString(speed / 1_000) + "kb/s"; |
| } else { |
| return Long.toString(speed) + "bytes/s"; |
| } |
| } |
| |
| private void sendByteData() { |
| if (elementOfNote != null && elementOfNote instanceof Device) { |
| DeviceId devId = (DeviceId) elementOfNote.id(); |
| Set<Link> links = linkService.getDeviceEgressLinks(devId); |
| Highlights highlights = getTotalBytes(links, devId); |
| sendHighlights(highlights); |
| } |
| } |
| |
| /** |
| * Gets the links connected to the highlighted device. |
| * Uses PortStatisticsService to get a load object of |
| * the links and find the total number of bytes sent out |
| * of the device via that link (src) and into the device |
| * via that link (dst), because dlink.two() gives a |
| * NullPointerException. Creates a label which displays |
| * the src and dst total bytes for the link. |
| */ |
| private Highlights getTotalBytes(Set<Link> links, DeviceId devId) { |
| LpLinkMap linkMap = new LpLinkMap(); |
| if (links != null) { |
| log.debug("Processing {} links", links.size()); |
| links.forEach(linkMap::add); |
| } else { |
| log.debug("No egress links found for device {}", devId); |
| } |
| |
| Highlights highlights = new Highlights(); |
| |
| for (LpLink dlink : linkMap.biLinks()) { |
| String bytes = "Out: " + getBytesString(portStatisticsService.load(dlink.one().src()).latest()) + " | In: " |
| + getBytesString(portStatisticsService.load(dlink.one().dst()).latest()); |
| dlink.makeImportant().setLabel(bytes); |
| highlights.add(dlink.highlight(null)); |
| } |
| return highlights; |
| } |
| |
| private String getBytesString(Long bytes) { |
| final long tb = (long) 1_000_000_000_000.0; |
| if (bytes > tb) { |
| return Long.toString(bytes / tb) + "Tb"; |
| } else if (bytes > 1_000_000_000) { |
| return Long.toString(bytes / 1_000_000_000) + "Gb"; |
| } else if (bytes > 1_000_000) { |
| return Long.toString(bytes / 1_000_000) + "Mb"; |
| } else if (bytes > 1_000) { |
| return Long.toString(bytes / 1_000) + "kb"; |
| } else { |
| return Long.toString(bytes) + "bytes"; |
| } |
| } |
| |
| } |