GUI2 Topo Added base common base for Topo2ViewMessageHandler and TopologyViewMessageHandlerBase
Change-Id: I6818b764a3dbafb134786c4f6cdddd051b0c88ba
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
index 5f30bf8..455b0f3 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandler.java
@@ -743,7 +743,8 @@
//=======================================================================
// Converts highlights to JSON format and sends the message to the client
- void sendHighlights(Highlights highlights) {
+ @Override
+ public void sendHighlights(Highlights highlights) {
sendMessage(highlightsMessage(highlights));
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
index 9e62410..93f41a6 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TopologyViewMessageHandlerBase.java
@@ -50,7 +50,7 @@
import org.onosproject.net.topology.Topology;
import org.onosproject.ui.JsonUtils;
import org.onosproject.ui.UiConnection;
-import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.impl.topo.TopoologyTrafficMessageHandlerAbstract;
import org.onosproject.ui.impl.topo.util.ServicesBundle;
import org.onosproject.ui.lion.LionBundle;
import org.onosproject.ui.topo.PropertyPanel;
@@ -77,7 +77,7 @@
/**
* Facility for creating messages bound for the topology viewer.
*/
-public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
+public abstract class TopologyViewMessageHandlerBase extends TopoologyTrafficMessageHandlerAbstract {
private static final String NO_GEO_VALUE = "0.0";
private static final String DASH = "-";
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java
index f45eb8d..9d9b3c3 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/TrafficMonitor.java
@@ -17,57 +17,31 @@
package org.onosproject.ui.impl;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
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.device.DeviceService;
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.FlowObjectiveIntent;
-import org.onosproject.net.intent.FlowRuleIntent;
-import org.onosproject.net.intent.HostToHostIntent;
-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.link.LinkService;
-import org.onosproject.ui.impl.topo.util.IntentSelection;
import org.onosproject.ui.impl.topo.util.ServicesBundle;
-import org.onosproject.ui.impl.topo.util.TopoIntentFilter;
import org.onosproject.ui.impl.topo.util.TrafficLink;
import org.onosproject.ui.impl.topo.util.TrafficLink.StatsType;
import org.onosproject.ui.impl.topo.util.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.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.stream.Collectors;
import static org.onosproject.net.DefaultEdgeLink.createEdgeLinks;
-import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.RELATED_INTENTS;
import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.SELECTED_INTENT;
@@ -80,10 +54,6 @@
LoggerFactory.getLogger(TrafficMonitor.class);
private final TopologyViewMessageHandler msgHandler;
- private final TopoIntentFilter intentFilter;
-
- private NodeSelection selectedNodes = null;
- private IntentSelection selectedIntents = null;
/**
@@ -95,10 +65,9 @@
*/
public TrafficMonitor(long trafficPeriod, ServicesBundle servicesBundle,
TopologyViewMessageHandler msgHandler) {
- super(trafficPeriod, servicesBundle);
+ super(trafficPeriod, servicesBundle, msgHandler);
this.msgHandler = msgHandler;
- intentFilter = new TopoIntentFilter(servicesBundle);
}
// =======================================================================
@@ -106,77 +75,9 @@
// monitor(Mode) is now implemented in the super class
- /**
- * 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()) {
- clearAll();
- } else {
- scheduleTask();
- sendDeviceLinkFlows();
- }
- break;
-
- case RELATED_INTENTS:
- if (selectedNodes.none()) {
- clearAll();
- } else {
- selectedIntents = new IntentSelection(selectedNodes, intentFilter);
- if (selectedIntents.none()) {
- clearAll();
- } 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.
@@ -261,12 +162,6 @@
selectedIntents = null;
}
-
- private void sendSelectedIntents() {
- log.debug("sendSelectedIntents: {}", selectedIntents);
- msgHandler.sendHighlights(intentGroup());
- }
-
// =======================================================================
// === Generate messages in JSON object node format
@@ -298,56 +193,6 @@
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;
- }
-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Counts all flow entries that egress on the links of the given device.
@@ -392,137 +237,4 @@
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 = services.intent()
- .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) {
- Collection<Link> l = new ArrayList<>();
- l.addAll(linkResources(installable));
- // Add cross connect links
- if (intent instanceof OpticalConnectivityIntent) {
- OpticalConnectivityIntent ocIntent = (OpticalConnectivityIntent) intent;
- LinkService linkService = services.link();
- DeviceService deviceService = services.device();
- l.addAll(linkService.getDeviceIngressLinks(ocIntent.getSrc().deviceId()).stream()
- .filter(i ->
- deviceService.getDevice(i.src().deviceId()).type() == Device.Type.SWITCH)
- .collect(Collectors.toList()));
- l.addAll(linkService.getDeviceEgressLinks(ocIntent.getDst().deviceId()).stream()
- .filter(e ->
- deviceService.getDevice(e.dst().deviceId()).type() == Device.Type.SWITCH)
- .collect(Collectors.toList()));
- }
- links = l;
- } else if (installable instanceof FlowObjectiveIntent) {
- links = linkResources(installable);
- } else if (installable instanceof LinkCollectionIntent) {
- links = ((LinkCollectionIntent) installable).links();
- } else if (installable instanceof OpticalPathIntent) {
- links = ((OpticalPathIntent) installable).path().links();
- }
-
- if (links == null) {
- links = Lists.newArrayList();
- }
-
- links = addEdgeLinksIfNeeded(intent, Lists.newArrayList(links));
-
- boolean isOptical = intent instanceof OpticalConnectivityIntent;
- processLinks(linkMap, links, flavor, isOptical, showTraffic);
- updateHighlights(highlights, links);
- }
- }
- }
- }
-
- private Iterable<Link> addEdgeLinksIfNeeded(Intent parentIntent,
- Collection<Link> links) {
- if (parentIntent instanceof HostToHostIntent) {
- links = new HashSet<>(links);
- HostToHostIntent h2h = (HostToHostIntent) parentIntent;
- Host h1 = services.host().getHost(h2h.one());
- Host h2 = services.host().getHost(h2h.two());
- links.add(createEdgeLink(h1, true));
- links.add(createEdgeLink(h2, true));
- }
- return 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));
- }
- }
-
}
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 43c3fdb..2f14ac4 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,39 +17,262 @@
package org.onosproject.ui.impl;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import org.onosproject.net.Device;
+import org.onosproject.net.ElementId;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intent.FlowObjectiveIntent;
+import org.onosproject.net.intent.FlowRuleIntent;
+import org.onosproject.net.intent.HostToHostIntent;
+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.link.LinkService;
import org.onosproject.net.statistic.PortStatisticsService.MetricType;
import org.onosproject.net.DefaultEdgeLink;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.statistic.Load;
+import org.onosproject.ui.impl.topo.TopoologyTrafficMessageHandlerAbstract;
+import org.onosproject.ui.impl.topo.util.IntentSelection;
import org.onosproject.ui.impl.topo.util.ServicesBundle;
+import org.onosproject.ui.impl.topo.util.TopoIntentFilter;
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.DeviceHighlight;
import org.onosproject.ui.topo.Highlights;
+import org.onosproject.ui.topo.HostHighlight;
+import org.onosproject.ui.topo.LinkHighlight;
+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.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
+import java.util.stream.Collectors;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
import static org.onosproject.net.statistic.PortStatisticsService.MetricType.BYTES;
import static org.onosproject.net.statistic.PortStatisticsService.MetricType.PACKETS;
import static org.onosproject.net.DefaultEdgeLink.createEdgeLinks;
import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.IDLE;
+import static org.onosproject.ui.impl.TrafficMonitorBase.Mode.SELECTED_INTENT;
/**
* Base superclass for traffic monitor (both 'classic' and 'topo2' versions).
*/
public abstract class TrafficMonitorBase extends AbstractTopoMonitor {
- private final Logger log = LoggerFactory.getLogger(getClass());
+ protected final Logger log = LoggerFactory.getLogger(getClass());
// 4 Kilo Bytes as threshold
protected static final double BPS_THRESHOLD = 4 * TopoUtils.N_KILO;
+ protected final TopoIntentFilter intentFilter;
+ protected IntentSelection selectedIntents = null;
+ protected final TopoologyTrafficMessageHandlerAbstract msgHandler;
+ protected NodeSelection selectedNodes = null;
+
+ protected void sendSelectedIntents() {
+ log.debug("sendSelectedIntents: {}", selectedIntents);
+ msgHandler.sendHighlights(intentGroup());
+ }
+
+ protected 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);
+ }
+ }
+ }
+
+ protected void colorLinks(Highlights highlights, TrafficLinkMap linkMap) {
+ for (TrafficLink tlink : linkMap.biLinks()) {
+ highlights.add(tlink.highlight(TrafficLink.StatsType.TAGGED));
+ }
+ }
+
+ protected void processLinks(TrafficLinkMap linkMap, Iterable<Link> links,
+ LinkHighlight.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);
+ }
+ }
+ }
+ }
+
+ protected void updateHighlights(Highlights highlights, Iterable<Link> links) {
+ for (Link link : links) {
+ ensureNodePresent(highlights, link.src().elementId());
+ ensureNodePresent(highlights, link.dst().elementId());
+ }
+ }
+
+ protected Iterable<Link> addEdgeLinksIfNeeded(Intent parentIntent,
+ Collection<Link> links) {
+ if (parentIntent instanceof HostToHostIntent) {
+ links = new HashSet<>(links);
+ HostToHostIntent h2h = (HostToHostIntent) parentIntent;
+ Host h1 = services.host().getHost(h2h.one());
+ Host h2 = services.host().getHost(h2h.two());
+ links.add(createEdgeLink(h1, true));
+ links.add(createEdgeLink(h2, true));
+ }
+ return links;
+ }
+
+ // Extracts links from the specified flow rule intent resources
+ protected 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();
+ }
+
+ protected void createTrafficLinks(Highlights highlights,
+ TrafficLinkMap linkMap, Set<Intent> intents,
+ LinkHighlight.Flavor flavor, boolean showTraffic) {
+ for (Intent intent : intents) {
+ List<Intent> installables = services.intent()
+ .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) {
+ Collection<Link> l = new ArrayList<>();
+ l.addAll(linkResources(installable));
+ // Add cross connect links
+ if (intent instanceof OpticalConnectivityIntent) {
+ OpticalConnectivityIntent ocIntent = (OpticalConnectivityIntent) intent;
+ LinkService linkService = services.link();
+ DeviceService deviceService = services.device();
+ l.addAll(linkService.getDeviceIngressLinks(ocIntent.getSrc().deviceId()).stream()
+ .filter(i ->
+ deviceService.getDevice(i.src().deviceId()).type() == Device.Type.SWITCH)
+ .collect(Collectors.toList()));
+ l.addAll(linkService.getDeviceEgressLinks(ocIntent.getDst().deviceId()).stream()
+ .filter(e ->
+ deviceService.getDevice(e.dst().deviceId()).type() == Device.Type.SWITCH)
+ .collect(Collectors.toList()));
+ }
+ links = l;
+ } else if (installable instanceof FlowObjectiveIntent) {
+ links = linkResources(installable);
+ } else if (installable instanceof LinkCollectionIntent) {
+ links = ((LinkCollectionIntent) installable).links();
+ } else if (installable instanceof OpticalPathIntent) {
+ links = ((OpticalPathIntent) installable).path().links();
+ }
+
+ if (links == null) {
+ links = Lists.newArrayList();
+ }
+
+ links = addEdgeLinksIfNeeded(intent, Lists.newArrayList(links));
+
+ boolean isOptical = intent instanceof OpticalConnectivityIntent;
+ processLinks(linkMap, links, flavor, isOptical, showTraffic);
+ updateHighlights(highlights, links);
+ }
+ }
+ }
+ }
+
+ protected 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, LinkHighlight.Flavor.SECONDARY_HIGHLIGHT, false);
+ createTrafficLinks(highlights, linkMap, primary, LinkHighlight.Flavor.PRIMARY_HIGHLIGHT, false);
+ colorLinks(highlights, linkMap);
+ }
+
+ protected 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;
+ }
+
+ protected 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(Highlights.Amount.MINIMALLY);
+ }
+ return highlights;
+ }
+
+ private void highlightIntentLinksWithTraffic(Highlights highlights,
+ Set<Intent> primary) {
+ TrafficLinkMap linkMap = new TrafficLinkMap();
+ createTrafficLinks(highlights, linkMap, primary, LinkHighlight.Flavor.PRIMARY_HIGHLIGHT, true);
+ colorLinks(highlights, linkMap);
+ }
/**
@@ -89,12 +312,16 @@
*
* @param trafficPeriod traffic task period in ms
* @param servicesBundle bundle of services
+ * @param msgHandler Traffic Message handler
*/
protected TrafficMonitorBase(long trafficPeriod,
- ServicesBundle servicesBundle) {
+ ServicesBundle servicesBundle,
+ TopoologyTrafficMessageHandlerAbstract msgHandler) {
this.trafficPeriod = trafficPeriod;
this.services = servicesBundle;
+ this.msgHandler = msgHandler;
timer = new Timer("uiTopo-" + getClass().getSimpleName());
+ intentFilter = new TopoIntentFilter(servicesBundle);
}
/**
@@ -149,6 +376,74 @@
}
/**
+ * 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()) {
+ clearAll();
+ } else {
+ scheduleTask();
+ sendDeviceLinkFlows();
+ }
+ break;
+
+ case RELATED_INTENTS:
+ if (selectedNodes.none()) {
+ clearAll();
+ } else {
+ selectedIntents = new IntentSelection(selectedNodes, intentFilter);
+ if (selectedIntents.none()) {
+ clearAll();
+ } else {
+ sendSelectedIntents();
+ }
+ }
+ break;
+
+ default:
+ log.debug("Unexpected call to monitor({}, {})", mode, nodeSelection);
+ clearAll();
+ break;
+ }
+ }
+
+ /**
+ * 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();
+ }
+
+ /**
* Subclass should compile and send appropriate highlights data showing
* flow traffic (bytes on links).
*/
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
index 608031c..041dce2 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiWebSocket.java
@@ -40,6 +40,7 @@
import org.onosproject.ui.impl.topo.Topo2OverlayCache;
import org.onosproject.ui.impl.topo.Topo2TrafficMessageHandler;
import org.onosproject.ui.impl.topo.Topo2ViewMessageHandler;
+import org.onosproject.ui.impl.topo.Traffic2Overlay;
import org.onosproject.ui.impl.topo.UiTopoSession;
import org.onosproject.ui.impl.topo.model.UiSharedTopologyModel;
import org.onosproject.ui.lion.LionBundle;
@@ -323,8 +324,10 @@
handlerCrossConnects(handlerInstances);
- log.debug("#handlers = {}, #overlays = {}",
- handlers.size(), overlayCache.size());
+ overlay2Cache.switchOverlay(null, Traffic2Overlay.OVERLAY_ID);
+
+ log.debug("#handlers = {}, #overlays = Topo: {}, Topo2: {}",
+ handlers.size(), overlayCache.size(), overlay2Cache.size());
}
private Map<String, LionBundle> generateLionMap(UiExtensionService service) {
@@ -404,6 +407,7 @@
handlers.get(Topo2TrafficMessageHandler.class);
if (topo2traffic != null) {
topo2mh.setTrafficHandler(topo2traffic);
+ topo2traffic.setOverlayCache(overlay2Cache);
} else {
log.error("No topo2 traffic handler found");
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2TrafficMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2TrafficMessageHandler.java
index 586ff8c..5f5d84d 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2TrafficMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2TrafficMessageHandler.java
@@ -17,36 +17,56 @@
package org.onosproject.ui.impl.topo;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import org.onlab.osgi.ServiceDirectory;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Host;
+import org.onosproject.net.HostId;
+import org.onosproject.net.HostLocation;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.HostToHostIntent;
+import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.ui.RequestHandler;
import org.onosproject.ui.UiConnection;
-import org.onosproject.ui.UiMessageHandler;
import org.onosproject.ui.impl.TrafficMonitorBase.Mode;
import org.onosproject.ui.impl.UiWebSocket;
import org.onosproject.ui.impl.topo.util.ServicesBundle;
import org.onosproject.ui.model.topo.UiLinkId;
import org.onosproject.ui.model.topo.UiSynthLink;
import org.onosproject.ui.topo.Highlights;
+import org.onosproject.ui.topo.NodeSelection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+import static org.onosproject.net.HostId.hostId;
import static org.onosproject.ui.topo.TopoJson.topo2HighlightsMessage;
/**
* Server-side component to handle messages pertaining to topo-2 traffic.
*/
-public class Topo2TrafficMessageHandler extends UiMessageHandler {
+public class Topo2TrafficMessageHandler extends TopoologyTrafficMessageHandlerAbstract {
private final Logger log = LoggerFactory.getLogger(getClass());
// === Inbound event identifiers
private static final String REQUEST_ALL_TRAFFIC = "topo2RequestAllTraffic";
private static final String CANCEL_TRAFFIC = "topo2CancelTraffic";
+ private static final String ADD_HOST_INTENT = "topo2AddHostIntent";
+ private static final String ADD_MULTI_SRC_INTENT = "topo2AddMultiSourceIntent";
+ private static final String REQ_RELATED_INTENTS = "topo2RequestRelatedIntents";
// field values
private static final String TRAFFIC_TYPE = "trafficType";
@@ -54,21 +74,29 @@
private static final String PORT_STATS_BIT_SEC = "portStatsBitSec";
private static final String PORT_STATS_PKT_SEC = "portStatsPktSec";
+ // fields
+ private static final String ONE = "one";
+ private static final String TWO = "two";
+ private static final String SRC = "src";
+ private static final String DST = "dst";
+
// configuration parameters
private static final long TRAFFIC_PERIOD = 5000;
protected ServicesBundle services;
-
+ private static final String MY_APP_ID = "org.onosproject.gui";
+ private ApplicationId appId;
private UiTopoSession topoSession;
- private Traffic2Monitor traffic;
+ private Topo2OverlayCache overlay2Cache;
+ private Traffic2Monitor traffic2;
@Override
public void init(UiConnection connection, ServiceDirectory directory) {
super.init(connection, directory);
-
+ appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
services = new ServicesBundle(directory);
- traffic = new Traffic2Monitor(TRAFFIC_PERIOD, services, this);
+ traffic2 = new Traffic2Monitor(TRAFFIC_PERIOD, services, this);
topoSession = ((UiWebSocket) connection).topoSession();
}
@@ -76,15 +104,26 @@
protected Collection<RequestHandler> createRequestHandlers() {
return ImmutableSet.of(
new Topo2AllTraffic(),
- new Topo2CancelTraffic()
+ new Topo2CancelTraffic(),
+ new Topo2AddHostIntent(),
+ new Topo2AddMultiSourceIntent()
);
}
/**
+ * Injects the topology overlay cache.
+ *
+ * @param overlay2Cache injected cache
+ */
+ public void setOverlayCache(Topo2OverlayCache overlay2Cache) {
+ this.overlay2Cache = overlay2Cache;
+ }
+
+ /**
* Shuts down the background traffic monitoring task.
*/
void ceaseAndDesist() {
- traffic.stopMonitoring();
+ traffic2.stopMonitoring();
}
/**
@@ -92,7 +131,8 @@
*
* @param highlights the highlights for transmission
*/
- void sendHighlights(Highlights highlights) {
+ @Override
+ public void sendHighlights(Highlights highlights) {
sendMessage(topo2HighlightsMessage(highlights));
}
@@ -121,15 +161,15 @@
switch (mode) {
case FLOW_STATS_BYTES:
- traffic.monitor(Mode.ALL_FLOW_TRAFFIC_BYTES);
+ traffic2.monitor(Mode.ALL_FLOW_TRAFFIC_BYTES);
break;
case PORT_STATS_BIT_SEC:
- traffic.monitor(Mode.ALL_PORT_TRAFFIC_BIT_PS);
+ traffic2.monitor(Mode.ALL_PORT_TRAFFIC_BIT_PS);
break;
case PORT_STATS_PKT_SEC:
- traffic.monitor(Mode.ALL_PORT_TRAFFIC_PKT_PS);
+ traffic2.monitor(Mode.ALL_PORT_TRAFFIC_PKT_PS);
break;
default:
@@ -147,9 +187,105 @@
@Override
public void process(ObjectNode payload) {
log.debug("CANCEL TRAFFIC");
- traffic.stopMonitoring();
+ traffic2.stopMonitoring();
}
}
+
+ private final class Topo2AddHostIntent extends RequestHandler {
+ private Topo2AddHostIntent() {
+ super(ADD_HOST_INTENT);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ // TODO: add protection against device ids and non-existent hosts.
+ HostId one = hostId(string(payload, ONE));
+ HostId two = hostId(string(payload, TWO));
+
+ HostToHostIntent intent = HostToHostIntent.builder()
+ .appId(appId)
+ .one(one)
+ .two(two)
+ .build();
+
+ services.intent().submit(intent);
+ if (overlay2Cache.isActive(Traffic2Overlay.OVERLAY_ID)) {
+ traffic2.monitor(intent);
+ }
+ }
+ }
+
+ private final class Topo2AddMultiSourceIntent extends RequestHandler {
+ private Topo2AddMultiSourceIntent() {
+ super(ADD_MULTI_SRC_INTENT);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ // TODO: add protection against device ids and non-existent hosts.
+ Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
+ HostId dst = hostId(string(payload, DST));
+ Host dstHost = services.host().getHost(dst);
+
+ Set<FilteredConnectPoint> ingressPoints = getHostLocations(src);
+
+ // FIXME: clearly, this is not enough
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchEthDst(dstHost.mac()).build();
+ TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
+
+ MultiPointToSinglePointIntent intent =
+ MultiPointToSinglePointIntent.builder()
+ .appId(appId)
+ .selector(selector)
+ .treatment(treatment)
+ .filteredIngressPoints(ingressPoints)
+ .filteredEgressPoint(new FilteredConnectPoint(dstHost.location()))
+ .build();
+
+ services.intent().submit(intent);
+ if (overlay2Cache.isActive(Traffic2Overlay.OVERLAY_ID)) {
+ traffic2.monitor(intent);
+ }
+ }
+ }
+
+ private final class ReqRelatedIntents extends RequestHandler {
+ private ReqRelatedIntents() {
+ super(REQ_RELATED_INTENTS);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ traffic2.monitor(Mode.RELATED_INTENTS, makeNodeSelection(payload));
+ }
+ }
+
+ // Produces a list of host ids from the specified JSON array.
+ private Set<HostId> getHostIds(ArrayNode ids) {
+ Set<HostId> hostIds = new HashSet<>();
+ for (JsonNode id : ids) {
+ hostIds.add(hostId(id.asText()));
+ }
+ return hostIds;
+ }
+
+ private Set<FilteredConnectPoint> getHostLocations(Set<HostId> hostIds) {
+ Set<FilteredConnectPoint> points = new HashSet<>();
+ for (HostId hostId : hostIds) {
+ points.add(new FilteredConnectPoint(getHostLocation(hostId)));
+ }
+ return points;
+ }
+
+ private HostLocation getHostLocation(HostId hostId) {
+ return services.host().getHost(hostId).location();
+ }
+
+ private NodeSelection makeNodeSelection(ObjectNode payload) {
+ return new NodeSelection(payload, services.device(), services.host(),
+ services.link());
+ }
}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
index 5fbb444..057a050 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Topo2ViewMessageHandler.java
@@ -67,7 +67,11 @@
private static final String CURRENT_REGION = "topo2CurrentRegion";
private static final String PEER_REGIONS = "topo2PeerRegions";
private static final String OVERLAYS = "topo2Overlays";
+ private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
+ // fields
+ private static final String ACTIVATE = "activate";
+ private static final String DEACTIVATE = "deactivate";
private UiTopoSession topoSession;
private Topo2Jsonifier t2json;
@@ -114,6 +118,19 @@
);
}
+ private final class TopoSelectOverlay extends RequestHandler {
+ private TopoSelectOverlay() {
+ super(TOPO_SELECT_OVERLAY);
+ }
+
+ @Override
+ public void process(ObjectNode payload) {
+ String deact = string(payload, DEACTIVATE);
+ String act = string(payload, ACTIVATE);
+ overlay2Cache.switchOverlay(deact, act);
+ }
+ }
+
// ==================================================================
private ObjectNode mkLayoutMessage(UiTopoLayout currentLayout) {
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/TopoologyTrafficMessageHandlerAbstract.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/TopoologyTrafficMessageHandlerAbstract.java
new file mode 100644
index 0000000..900f4df
--- /dev/null
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/TopoologyTrafficMessageHandlerAbstract.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019-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.ui.impl.topo;
+
+import org.onosproject.ui.UiMessageHandler;
+import org.onosproject.ui.topo.Highlights;
+
+/**
+ * Base superclass for traffic message handler (both 'classic' and 'topo2' versions).
+ */
+public abstract class TopoologyTrafficMessageHandlerAbstract extends UiMessageHandler {
+ public abstract void sendHighlights(Highlights highlights);
+}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java
index 4e78525..d0d40bd 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Monitor.java
@@ -54,7 +54,7 @@
*/
public Traffic2Monitor(long trafficPeriod, ServicesBundle servicesBundle,
Topo2TrafficMessageHandler msgHandler) {
- super(trafficPeriod, servicesBundle);
+ super(trafficPeriod, servicesBundle, msgHandler);
this.msgHandler = msgHandler;
}
@@ -90,7 +90,8 @@
@Override
protected void sendSelectedIntentTraffic() {
- log.debug("sendSelectedIntentTraffic: NOT IMPLEMENTED YET");
+ log.debug("sendSelectedIntentTraffic: {}", selectedIntents);
+ msgHandler.sendHighlights(intentTraffic());
}
@Override
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Overlay.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Overlay.java
index 26692fe..057a5987 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Overlay.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/Traffic2Overlay.java
@@ -29,7 +29,7 @@
private final Logger log = LoggerFactory.getLogger(getClass());
// NOTE: this must match the ID defined in topo2TrafficOverlay.js
- private static final String OVERLAY_ID = "traffic-2-overlay";
+ public static final String OVERLAY_ID = "traffic-2-overlay";
/**
* Creates a traffic overlay instance.
diff --git a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/panel/details/details.component.ts b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/panel/details/details.component.ts
index 21ad66e..79118b8 100644
--- a/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/panel/details/details.component.ts
+++ b/web/gui2-topo-lib/projects/gui2-topo-lib/src/lib/panel/details/details.component.ts
@@ -318,13 +318,13 @@
const ids: string[] = [];
Object.values(this.showDetails.propValues).forEach((v) => ids.push(v));
if (path === 'relatedIntents' && this.showDetails.id === 'multiple') {
- this.wss.sendEvent('requestRelatedIntents', {
+ this.wss.sendEvent('topo2RequestRelatedIntents', {
'ids': ids,
'hover': ''
});
} else if (path === 'create_h2h_flow' && this.showDetails.id === 'multiple') {
- this.wss.sendEvent('addHostIntent', {
+ this.wss.sendEvent('topo2AddHostIntent', {
'one': ids[0],
'two': ids[1],
'ids': ids
@@ -332,7 +332,7 @@
} else if (path === 'create_msrc_flow' && this.showDetails.id === 'multiple') {
// Should only happen when there are 3 or more ids
- this.wss.sendEvent('addMultiSourceIntent', {
+ this.wss.sendEvent('topo2AddMultiSourceIntent', {
'src': ids.slice(0, ids.length - 1),
'dst': ids[ids.length - 1],
'ids': ids