diff options
Diffstat (limited to 'framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java')
-rw-r--r-- | framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java | 675 |
1 files changed, 0 insertions, 675 deletions
diff --git a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java b/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java deleted file mode 100644 index 3d733f9e..00000000 --- a/framework/src/onos/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Copyright 2015 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.ui.impl; - -import com.google.common.collect.ImmutableList; -import org.onosproject.net.Device; -import org.onosproject.net.DeviceId; -import org.onosproject.net.ElementId; -import org.onosproject.net.Host; -import org.onosproject.net.HostId; -import org.onosproject.net.Link; -import org.onosproject.net.PortNumber; -import org.onosproject.net.flow.FlowEntry; -import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.flow.instructions.Instruction; -import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; -import org.onosproject.net.intent.FlowRuleIntent; -import org.onosproject.net.intent.Intent; -import org.onosproject.net.intent.LinkCollectionIntent; -import org.onosproject.net.intent.OpticalConnectivityIntent; -import org.onosproject.net.intent.OpticalPathIntent; -import org.onosproject.net.intent.PathIntent; -import org.onosproject.net.statistic.Load; -import org.onosproject.ui.impl.topo.IntentSelection; -import org.onosproject.ui.impl.topo.ServicesBundle; -import org.onosproject.ui.impl.topo.TopoIntentFilter; -import org.onosproject.ui.impl.topo.TrafficLink; -import org.onosproject.ui.impl.topo.TrafficLink.StatsType; -import org.onosproject.ui.impl.topo.TrafficLinkMap; -import org.onosproject.ui.topo.DeviceHighlight; -import org.onosproject.ui.topo.Highlights; -import org.onosproject.ui.topo.Highlights.Amount; -import org.onosproject.ui.topo.HostHighlight; -import org.onosproject.ui.topo.LinkHighlight.Flavor; -import org.onosproject.ui.topo.NodeHighlight; -import org.onosproject.ui.topo.NodeSelection; -import org.onosproject.ui.topo.TopoUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; - -import static org.onosproject.net.DefaultEdgeLink.createEdgeLink; -import static org.onosproject.ui.impl.TrafficMonitor.Mode.*; - -/** - * Encapsulates the behavior of monitoring specific traffic patterns. - */ -public class TrafficMonitor { - - // 4 Kilo Bytes as threshold - private static final double BPS_THRESHOLD = 4 * TopoUtils.KILO; - - private static final Logger log = - LoggerFactory.getLogger(TrafficMonitor.class); - - /** - * Designates the different modes of operation. - */ - public enum Mode { - IDLE, - ALL_FLOW_TRAFFIC, - ALL_PORT_TRAFFIC, - DEV_LINK_FLOWS, - RELATED_INTENTS, - SELECTED_INTENT - } - - private final long trafficPeriod; - private final ServicesBundle servicesBundle; - private final TopologyViewMessageHandler msgHandler; - private final TopoIntentFilter intentFilter; - - private final Timer timer = new Timer("topo-traffic"); - - private TimerTask trafficTask = null; - private Mode mode = IDLE; - private NodeSelection selectedNodes = null; - private IntentSelection selectedIntents = null; - - - /** - * Constructs a traffic monitor. - * - * @param trafficPeriod traffic task period in ms - * @param servicesBundle bundle of services - * @param msgHandler our message handler - */ - public TrafficMonitor(long trafficPeriod, ServicesBundle servicesBundle, - TopologyViewMessageHandler msgHandler) { - this.trafficPeriod = trafficPeriod; - this.servicesBundle = servicesBundle; - this.msgHandler = msgHandler; - - intentFilter = new TopoIntentFilter(servicesBundle); - } - - // ======================================================================= - // === API === - - /** - * Monitor for traffic data to be sent back to the web client, under - * the given mode. This causes a background traffic task to be - * scheduled to repeatedly compute and transmit the appropriate traffic - * data to the client. - * <p> - * The monitoring mode is expected to be one of: - * <ul> - * <li>ALL_FLOW_TRAFFIC</li> - * <li>ALL_PORT_TRAFFIC</li> - * <li>SELECTED_INTENT</li> - * </ul> - * - * @param mode monitoring mode - */ - public synchronized void monitor(Mode mode) { - log.debug("monitor: {}", mode); - this.mode = mode; - - switch (mode) { - case ALL_FLOW_TRAFFIC: - clearSelection(); - scheduleTask(); - sendAllFlowTraffic(); - break; - - case ALL_PORT_TRAFFIC: - clearSelection(); - scheduleTask(); - sendAllPortTraffic(); - break; - - case SELECTED_INTENT: - scheduleTask(); - sendSelectedIntentTraffic(); - break; - - default: - log.debug("Unexpected call to monitor({})", mode); - clearAll(); - break; - } - } - - /** - * Monitor for traffic data to be sent back to the web client, under - * the given mode, using the given selection of devices and hosts. - * In the case of "device link flows", this causes a background traffic - * task to be scheduled to repeatedly compute and transmit the appropriate - * traffic data to the client. In the case of "related intents", no - * repeating task is scheduled. - * <p> - * The monitoring mode is expected to be one of: - * <ul> - * <li>DEV_LINK_FLOWS</li> - * <li>RELATED_INTENTS</li> - * </ul> - * - * @param mode monitoring mode - * @param nodeSelection how to select a node - */ - public synchronized void monitor(Mode mode, NodeSelection nodeSelection) { - log.debug("monitor: {} -- {}", mode, nodeSelection); - this.mode = mode; - this.selectedNodes = nodeSelection; - - switch (mode) { - case DEV_LINK_FLOWS: - // only care about devices (not hosts) - if (selectedNodes.devicesWithHover().isEmpty()) { - sendClearAll(); - } else { - scheduleTask(); - sendDeviceLinkFlows(); - } - break; - - case RELATED_INTENTS: - if (selectedNodes.none()) { - sendClearAll(); - } else { - selectedIntents = new IntentSelection(selectedNodes, intentFilter); - if (selectedIntents.none()) { - sendClearAll(); - } else { - sendSelectedIntents(); - } - } - break; - - default: - log.debug("Unexpected call to monitor({}, {})", mode, nodeSelection); - clearAll(); - break; - } - } - - // TODO: move this out to the "h2h/multi-intent app" - /** - * Monitor for traffic data to be sent back to the web client, for the - * given intent. - * - * @param intent the intent to monitor - */ - public synchronized void monitor(Intent intent) { - log.debug("monitor intent: {}", intent.id()); - selectedNodes = null; - selectedIntents = new IntentSelection(intent); - mode = SELECTED_INTENT; - scheduleTask(); - sendSelectedIntentTraffic(); - } - - /** - * Selects the next intent in the select group (if there is one), - * and sends highlighting data back to the web client to display - * which path is selected. - */ - public synchronized void selectNextIntent() { - if (selectedIntents != null) { - selectedIntents.next(); - sendSelectedIntents(); - if (mode == SELECTED_INTENT) { - mode = RELATED_INTENTS; - } - } - } - - /** - * Selects the previous intent in the select group (if there is one), - * and sends highlighting data back to the web client to display - * which path is selected. - */ - public synchronized void selectPreviousIntent() { - if (selectedIntents != null) { - selectedIntents.prev(); - sendSelectedIntents(); - if (mode == SELECTED_INTENT) { - mode = RELATED_INTENTS; - } - } - } - - /** - * Resends selected intent traffic data. This is called, for example, - * when the system detects an intent update happened. - */ - public synchronized void pokeIntent() { - if (mode == SELECTED_INTENT) { - sendSelectedIntentTraffic(); - } - } - - /** - * Stop all traffic monitoring. - */ - public synchronized void stopMonitoring() { - log.debug("STOP monitoring"); - if (mode != IDLE) { - sendClearAll(); - } - } - - - // ======================================================================= - // === Helper methods === - - private void sendClearAll() { - clearAll(); - sendClearHighlights(); - } - - private void clearAll() { - this.mode = IDLE; - clearSelection(); - cancelTask(); - } - - private void clearSelection() { - selectedNodes = null; - selectedIntents = null; - } - - private synchronized void scheduleTask() { - if (trafficTask == null) { - log.debug("Starting up background traffic task..."); - trafficTask = new TrafficUpdateTask(); - timer.schedule(trafficTask, trafficPeriod, trafficPeriod); - } else { - log.debug("(traffic task already running)"); - } - } - - private synchronized void cancelTask() { - if (trafficTask != null) { - trafficTask.cancel(); - trafficTask = null; - } - } - - private void sendAllFlowTraffic() { - log.debug("sendAllFlowTraffic"); - msgHandler.sendHighlights(trafficSummary(StatsType.FLOW_STATS)); - } - - private void sendAllPortTraffic() { - log.debug("sendAllPortTraffic"); - msgHandler.sendHighlights(trafficSummary(StatsType.PORT_STATS)); - } - - private void sendDeviceLinkFlows() { - log.debug("sendDeviceLinkFlows: {}", selectedNodes); - msgHandler.sendHighlights(deviceLinkFlows()); - } - - private void sendSelectedIntents() { - log.debug("sendSelectedIntents: {}", selectedIntents); - msgHandler.sendHighlights(intentGroup()); - } - - private void sendSelectedIntentTraffic() { - log.debug("sendSelectedIntentTraffic: {}", selectedIntents); - msgHandler.sendHighlights(intentTraffic()); - } - - private void sendClearHighlights() { - log.debug("sendClearHighlights"); - msgHandler.sendHighlights(new Highlights()); - } - - // ======================================================================= - // === Generate messages in JSON object node format - - private Highlights trafficSummary(StatsType type) { - Highlights highlights = new Highlights(); - - TrafficLinkMap linkMap = new TrafficLinkMap(); - compileLinks(linkMap); - addEdgeLinks(linkMap); - - for (TrafficLink tlink : linkMap.biLinks()) { - if (type == StatsType.FLOW_STATS) { - attachFlowLoad(tlink); - } else if (type == StatsType.PORT_STATS) { - attachPortLoad(tlink); - } - - // we only want to report on links deemed to have traffic - if (tlink.hasTraffic()) { - highlights.add(tlink.highlight(type)); - } - } - return highlights; - } - - // create highlights for links, showing flows for selected devices. - private Highlights deviceLinkFlows() { - Highlights highlights = new Highlights(); - - if (selectedNodes != null && !selectedNodes.devicesWithHover().isEmpty()) { - // capture flow counts on bilinks - TrafficLinkMap linkMap = new TrafficLinkMap(); - - for (Device device : selectedNodes.devicesWithHover()) { - Map<Link, Integer> counts = getLinkFlowCounts(device.id()); - for (Link link : counts.keySet()) { - TrafficLink tlink = linkMap.add(link); - tlink.addFlows(counts.get(link)); - } - } - - // now report on our collated links - for (TrafficLink tlink : linkMap.biLinks()) { - highlights.add(tlink.highlight(StatsType.FLOW_COUNT)); - } - - } - return highlights; - } - - private Highlights intentGroup() { - Highlights highlights = new Highlights(); - - if (selectedIntents != null && !selectedIntents.none()) { - // If 'all' intents are selected, they will all have primary - // highlighting; otherwise, the specifically selected intent will - // have primary highlighting, and the remainder will have secondary - // highlighting. - Set<Intent> primary; - Set<Intent> secondary; - int count = selectedIntents.size(); - - Set<Intent> allBut = new HashSet<>(selectedIntents.intents()); - Intent current; - - if (selectedIntents.all()) { - primary = allBut; - secondary = Collections.emptySet(); - log.debug("Highlight all intents ({})", count); - } else { - current = selectedIntents.current(); - primary = new HashSet<>(); - primary.add(current); - allBut.remove(current); - secondary = allBut; - log.debug("Highlight intent: {} ([{}] of {})", - current.id(), selectedIntents.index(), count); - } - - highlightIntentLinks(highlights, primary, secondary); - } - return highlights; - } - - private Highlights intentTraffic() { - Highlights highlights = new Highlights(); - - if (selectedIntents != null && selectedIntents.single()) { - Intent current = selectedIntents.current(); - Set<Intent> primary = new HashSet<>(); - primary.add(current); - log.debug("Highlight traffic for intent: {} ([{}] of {})", - current.id(), selectedIntents.index(), selectedIntents.size()); - - highlightIntentLinksWithTraffic(highlights, primary); - highlights.subdueAllElse(Amount.MINIMALLY); - } - return highlights; - } - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - private void compileLinks(TrafficLinkMap linkMap) { - servicesBundle.linkService().getLinks().forEach(linkMap::add); - } - - private void addEdgeLinks(TrafficLinkMap linkMap) { - servicesBundle.hostService().getHosts().forEach(host -> { - linkMap.add(createEdgeLink(host, true)); - linkMap.add(createEdgeLink(host, false)); - }); - } - - private Load getLinkFlowLoad(Link link) { - if (link != null && link.src().elementId() instanceof DeviceId) { - return servicesBundle.flowStatsService().load(link); - } - return null; - } - - private void attachFlowLoad(TrafficLink link) { - link.addLoad(getLinkFlowLoad(link.one())); - link.addLoad(getLinkFlowLoad(link.two())); - } - - private void attachPortLoad(TrafficLink link) { - // 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 = servicesBundle.portStatsService().load(one.src()); - Load egressDst = servicesBundle.portStatsService().load(one.dst()); - link.addLoad(maxLoad(egressSrc, egressDst), BPS_THRESHOLD); -// link.addLoad(maxLoad(egressSrc, egressDst), 10); // DEBUG ONLY!! - } - - private Load maxLoad(Load a, Load b) { - if (a == null) { - return b; - } - if (b == null) { - return a; - } - return a.rate() > b.rate() ? a : b; - } - - // Counts all flow entries that egress on the links of the given device. - private Map<Link, Integer> getLinkFlowCounts(DeviceId deviceId) { - // get the flows for the device - List<FlowEntry> entries = new ArrayList<>(); - for (FlowEntry flowEntry : servicesBundle.flowService() - .getFlowEntries(deviceId)) { - entries.add(flowEntry); - } - - // get egress links from device, and include edge links - Set<Link> links = new HashSet<>(servicesBundle.linkService() - .getDeviceEgressLinks(deviceId)); - Set<Host> hosts = servicesBundle.hostService().getConnectedHosts(deviceId); - if (hosts != null) { - for (Host host : hosts) { - links.add(createEdgeLink(host, false)); - } - } - - // compile flow counts per link - Map<Link, Integer> counts = new HashMap<>(); - for (Link link : links) { - counts.put(link, getEgressFlows(link, entries)); - } - return counts; - } - - // Counts all entries that egress on the link source port. - private int getEgressFlows(Link link, List<FlowEntry> entries) { - int count = 0; - PortNumber out = link.src().port(); - for (FlowEntry entry : entries) { - TrafficTreatment treatment = entry.treatment(); - for (Instruction instruction : treatment.allInstructions()) { - if (instruction.type() == Instruction.Type.OUTPUT && - ((OutputInstruction) instruction).port().equals(out)) { - count++; - } - } - } - return count; - } - - private void highlightIntentLinks(Highlights highlights, - Set<Intent> primary, Set<Intent> secondary) { - TrafficLinkMap linkMap = new TrafficLinkMap(); - // NOTE: highlight secondary first, then primary, so that links shared - // by intents are colored correctly ("last man wins") - createTrafficLinks(highlights, linkMap, secondary, Flavor.SECONDARY_HIGHLIGHT, false); - createTrafficLinks(highlights, linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, false); - colorLinks(highlights, linkMap); - } - - private void highlightIntentLinksWithTraffic(Highlights highlights, - Set<Intent> primary) { - TrafficLinkMap linkMap = new TrafficLinkMap(); - createTrafficLinks(highlights, linkMap, primary, Flavor.PRIMARY_HIGHLIGHT, true); - colorLinks(highlights, linkMap); - } - - private void createTrafficLinks(Highlights highlights, - TrafficLinkMap linkMap, Set<Intent> intents, - Flavor flavor, boolean showTraffic) { - for (Intent intent : intents) { - List<Intent> installables = servicesBundle.intentService() - .getInstallableIntents(intent.key()); - Iterable<Link> links = null; - if (installables != null) { - for (Intent installable : installables) { - - if (installable instanceof PathIntent) { - links = ((PathIntent) installable).path().links(); - } else if (installable instanceof FlowRuleIntent) { - links = linkResources(installable); - } else if (installable instanceof LinkCollectionIntent) { - links = ((LinkCollectionIntent) installable).links(); - } else if (installable instanceof OpticalPathIntent) { - links = ((OpticalPathIntent) installable).path().links(); - } - - boolean isOptical = intent instanceof OpticalConnectivityIntent; - processLinks(linkMap, links, flavor, isOptical, showTraffic); - updateHighlights(highlights, links); - } - } - } - } - - private void updateHighlights(Highlights highlights, Iterable<Link> links) { - for (Link link : links) { - ensureNodePresent(highlights, link.src().elementId()); - ensureNodePresent(highlights, link.dst().elementId()); - } - } - - private void ensureNodePresent(Highlights highlights, ElementId eid) { - String id = eid.toString(); - NodeHighlight nh = highlights.getNode(id); - if (nh == null) { - if (eid instanceof DeviceId) { - nh = new DeviceHighlight(id); - highlights.add((DeviceHighlight) nh); - } else if (eid instanceof HostId) { - nh = new HostHighlight(id); - highlights.add((HostHighlight) nh); - } - } - } - - // Extracts links from the specified flow rule intent resources - private Collection<Link> linkResources(Intent installable) { - ImmutableList.Builder<Link> builder = ImmutableList.builder(); - installable.resources().stream().filter(r -> r instanceof Link) - .forEach(r -> builder.add((Link) r)); - return builder.build(); - } - - private void processLinks(TrafficLinkMap linkMap, Iterable<Link> links, - Flavor flavor, boolean isOptical, - boolean showTraffic) { - if (links != null) { - for (Link link : links) { - TrafficLink tlink = linkMap.add(link); - tlink.tagFlavor(flavor); - tlink.optical(isOptical); - if (showTraffic) { - tlink.addLoad(getLinkFlowLoad(link)); - tlink.antMarch(true); - } - } - } - } - - private void colorLinks(Highlights highlights, TrafficLinkMap linkMap) { - for (TrafficLink tlink : linkMap.biLinks()) { - highlights.add(tlink.highlight(StatsType.TAGGED)); - } - } - - // ======================================================================= - // === Background Task - - // Provides periodic update of traffic information to the client - private class TrafficUpdateTask extends TimerTask { - @Override - public void run() { - try { - switch (mode) { - case ALL_FLOW_TRAFFIC: - sendAllFlowTraffic(); - break; - case ALL_PORT_TRAFFIC: - sendAllPortTraffic(); - break; - case DEV_LINK_FLOWS: - sendDeviceLinkFlows(); - break; - case SELECTED_INTENT: - sendSelectedIntentTraffic(); - break; - - default: - // RELATED_INTENTS and IDLE modes should never invoke - // the background task, but if they do, they have - // nothing to do - break; - } - - } catch (Exception e) { - log.warn("Unable to process traffic task due to {}", e.getMessage()); - log.warn("Boom!", e); - } - } - } -} |