Enhancing the GUI traffic-related code.
Fixed a defect in reactive forwarding. Change-Id: I1a91f6e5f57b39425ef06092c82b06d04c9b59a0
Showing
6 changed files
with
243 additions
and
23 deletions
... | @@ -132,8 +132,8 @@ public class ReactiveForwarding { | ... | @@ -132,8 +132,8 @@ public class ReactiveForwarding { |
132 | InboundPacket pkt = context.inPacket(); | 132 | InboundPacket pkt = context.inPacket(); |
133 | Ethernet ethPkt = pkt.parsed(); | 133 | Ethernet ethPkt = pkt.parsed(); |
134 | 134 | ||
135 | - // Bail if this is deemed to be a control packet. | 135 | + // Bail if this is deemed to be a control or IPv6 multicast packet. |
136 | - if (isControlPacket(ethPkt)) { | 136 | + if (isControlPacket(ethPkt) || isIpv6Multicast(ethPkt)) { |
137 | return; | 137 | return; |
138 | } | 138 | } |
139 | 139 | ||
... | @@ -194,6 +194,11 @@ public class ReactiveForwarding { | ... | @@ -194,6 +194,11 @@ public class ReactiveForwarding { |
194 | return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN; | 194 | return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN; |
195 | } | 195 | } |
196 | 196 | ||
197 | + // Indicated whether this is an IPv6 multicast packet. | ||
198 | + private boolean isIpv6Multicast(Ethernet eth) { | ||
199 | + return eth.getEtherType() == Ethernet.TYPE_IPV6 && eth.isMulticast(); | ||
200 | + } | ||
201 | + | ||
197 | // Selects a path from the given set that does not lead back to the | 202 | // Selects a path from the given set that does not lead back to the |
198 | // specified port. | 203 | // specified port. |
199 | private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) { | 204 | private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) { | ... | ... |
core/api/src/main/java/org/onlab/onos/net/intent/constraint/AsymmetricPathConstraint.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.onos.net.intent.constraint; | ||
17 | + | ||
18 | +import org.onlab.onos.net.Link; | ||
19 | +import org.onlab.onos.net.Path; | ||
20 | +import org.onlab.onos.net.intent.Constraint; | ||
21 | +import org.onlab.onos.net.resource.LinkResourceService; | ||
22 | + | ||
23 | +import java.util.Objects; | ||
24 | + | ||
25 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
26 | + | ||
27 | +/** | ||
28 | + * Constraint that serves as a request for asymmetric bi-directional path. | ||
29 | + */ | ||
30 | +public class AsymmetricPathConstraint implements Constraint { | ||
31 | + | ||
32 | + @Override | ||
33 | + public double cost(Link link, LinkResourceService resourceService) { | ||
34 | + return 1; | ||
35 | + } | ||
36 | + | ||
37 | + @Override | ||
38 | + public boolean validate(Path path, LinkResourceService resourceService) { | ||
39 | + return true; | ||
40 | + } | ||
41 | + | ||
42 | + @Override | ||
43 | + public int hashCode() { | ||
44 | + return Objects.hashCode(true); | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public boolean equals(Object obj) { | ||
49 | + if (this == obj) { | ||
50 | + return true; | ||
51 | + } | ||
52 | + if (obj == null || getClass() != obj.getClass()) { | ||
53 | + return false; | ||
54 | + } | ||
55 | + return true; | ||
56 | + } | ||
57 | + | ||
58 | + @Override | ||
59 | + public String toString() { | ||
60 | + return toStringHelper(this).toString(); | ||
61 | + } | ||
62 | +} |
... | @@ -20,15 +20,20 @@ import org.apache.felix.scr.annotations.Component; | ... | @@ -20,15 +20,20 @@ import org.apache.felix.scr.annotations.Component; |
20 | import org.apache.felix.scr.annotations.Deactivate; | 20 | import org.apache.felix.scr.annotations.Deactivate; |
21 | import org.apache.felix.scr.annotations.Reference; | 21 | import org.apache.felix.scr.annotations.Reference; |
22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
23 | +import org.onlab.onos.net.DefaultLink; | ||
24 | +import org.onlab.onos.net.DefaultPath; | ||
23 | import org.onlab.onos.net.Host; | 25 | import org.onlab.onos.net.Host; |
26 | +import org.onlab.onos.net.Link; | ||
24 | import org.onlab.onos.net.Path; | 27 | import org.onlab.onos.net.Path; |
25 | import org.onlab.onos.net.flow.TrafficSelector; | 28 | import org.onlab.onos.net.flow.TrafficSelector; |
26 | import org.onlab.onos.net.host.HostService; | 29 | import org.onlab.onos.net.host.HostService; |
27 | import org.onlab.onos.net.intent.HostToHostIntent; | 30 | import org.onlab.onos.net.intent.HostToHostIntent; |
28 | import org.onlab.onos.net.intent.Intent; | 31 | import org.onlab.onos.net.intent.Intent; |
29 | import org.onlab.onos.net.intent.PathIntent; | 32 | import org.onlab.onos.net.intent.PathIntent; |
33 | +import org.onlab.onos.net.intent.constraint.AsymmetricPathConstraint; | ||
30 | import org.onlab.onos.net.resource.LinkResourceAllocations; | 34 | import org.onlab.onos.net.resource.LinkResourceAllocations; |
31 | 35 | ||
36 | +import java.util.ArrayList; | ||
32 | import java.util.Arrays; | 37 | import java.util.Arrays; |
33 | import java.util.List; | 38 | import java.util.List; |
34 | import java.util.Set; | 39 | import java.util.Set; |
... | @@ -58,8 +63,10 @@ public class HostToHostIntentCompiler | ... | @@ -58,8 +63,10 @@ public class HostToHostIntentCompiler |
58 | @Override | 63 | @Override |
59 | public List<Intent> compile(HostToHostIntent intent, List<Intent> installable, | 64 | public List<Intent> compile(HostToHostIntent intent, List<Intent> installable, |
60 | Set<LinkResourceAllocations> resources) { | 65 | Set<LinkResourceAllocations> resources) { |
66 | + boolean isAsymmetric = intent.constraints().contains(new AsymmetricPathConstraint()); | ||
61 | Path pathOne = getPath(intent, intent.one(), intent.two()); | 67 | Path pathOne = getPath(intent, intent.one(), intent.two()); |
62 | - Path pathTwo = getPath(intent, intent.two(), intent.one()); | 68 | + Path pathTwo = isAsymmetric ? |
69 | + getPath(intent, intent.two(), intent.one()) : invertPath(pathOne); | ||
63 | 70 | ||
64 | Host one = hostService.getHost(intent.one()); | 71 | Host one = hostService.getHost(intent.one()); |
65 | Host two = hostService.getHost(intent.two()); | 72 | Host two = hostService.getHost(intent.two()); |
... | @@ -68,6 +75,23 @@ public class HostToHostIntentCompiler | ... | @@ -68,6 +75,23 @@ public class HostToHostIntentCompiler |
68 | createPathIntent(pathTwo, two, one, intent)); | 75 | createPathIntent(pathTwo, two, one, intent)); |
69 | } | 76 | } |
70 | 77 | ||
78 | + // Inverts the specified path. This makes an assumption that each link in | ||
79 | + // the path has a reverse link available. Under most circumstances, this | ||
80 | + // assumption will hold. | ||
81 | + private Path invertPath(Path path) { | ||
82 | + List<Link> reverseLinks = new ArrayList<>(path.links().size()); | ||
83 | + for (Link link : path.links()) { | ||
84 | + reverseLinks.add(0, reverseLink(link)); | ||
85 | + } | ||
86 | + return new DefaultPath(path.providerId(), reverseLinks, path.cost()); | ||
87 | + } | ||
88 | + | ||
89 | + // Produces a reverse variant of the specified link. | ||
90 | + private Link reverseLink(Link link) { | ||
91 | + return new DefaultLink(link.providerId(), link.dst(), link.src(), | ||
92 | + link.type(), link.state(), link.isDurable()); | ||
93 | + } | ||
94 | + | ||
71 | // Creates a path intent from the specified path and original connectivity intent. | 95 | // Creates a path intent from the specified path and original connectivity intent. |
72 | private Intent createPathIntent(Path path, Host src, Host dst, | 96 | private Intent createPathIntent(Path path, Host src, Host dst, |
73 | HostToHostIntent intent) { | 97 | HostToHostIntent intent) { | ... | ... |
... | @@ -31,14 +31,16 @@ import java.util.Map; | ... | @@ -31,14 +31,16 @@ import java.util.Map; |
31 | */ | 31 | */ |
32 | public class Ethernet extends BasePacket { | 32 | public class Ethernet extends BasePacket { |
33 | private static final String HEXES = "0123456789ABCDEF"; | 33 | private static final String HEXES = "0123456789ABCDEF"; |
34 | - public static final short TYPE_ARP = 0x0806; | 34 | + public static final short TYPE_ARP = (short) 0x0806; |
35 | public static final short TYPE_RARP = (short) 0x8035; | 35 | public static final short TYPE_RARP = (short) 0x8035; |
36 | - public static final short TYPE_IPV4 = 0x0800; | 36 | + public static final short TYPE_IPV4 = (short) 0x0800; |
37 | + public static final short TYPE_IPV6 = (short) 0x86dd; | ||
37 | public static final short TYPE_LLDP = (short) 0x88cc; | 38 | public static final short TYPE_LLDP = (short) 0x88cc; |
38 | public static final short TYPE_BSN = (short) 0x8942; | 39 | public static final short TYPE_BSN = (short) 0x8942; |
39 | public static final short VLAN_UNTAGGED = (short) 0xffff; | 40 | public static final short VLAN_UNTAGGED = (short) 0xffff; |
40 | public static final short MPLS_UNICAST = (short) 0x8847; | 41 | public static final short MPLS_UNICAST = (short) 0x8847; |
41 | public static final short MPLS_MULTICAST = (short) 0x8848; | 42 | public static final short MPLS_MULTICAST = (short) 0x8848; |
43 | + | ||
42 | public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes | 44 | public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes |
43 | public static final Map<Short, Class<? extends IPacket>> ETHER_TYPE_CLASS_MAP = | 45 | public static final Map<Short, Class<? extends IPacket>> ETHER_TYPE_CLASS_MAP = |
44 | new HashMap<>(); | 46 | new HashMap<>(); | ... | ... |
... | @@ -36,6 +36,7 @@ import org.onlab.onos.net.Host; | ... | @@ -36,6 +36,7 @@ import org.onlab.onos.net.Host; |
36 | import org.onlab.onos.net.HostId; | 36 | import org.onlab.onos.net.HostId; |
37 | import org.onlab.onos.net.HostLocation; | 37 | import org.onlab.onos.net.HostLocation; |
38 | import org.onlab.onos.net.Link; | 38 | import org.onlab.onos.net.Link; |
39 | +import org.onlab.onos.net.LinkKey; | ||
39 | import org.onlab.onos.net.PortNumber; | 40 | import org.onlab.onos.net.PortNumber; |
40 | import org.onlab.onos.net.device.DeviceEvent; | 41 | import org.onlab.onos.net.device.DeviceEvent; |
41 | import org.onlab.onos.net.device.DeviceService; | 42 | import org.onlab.onos.net.device.DeviceService; |
... | @@ -66,6 +67,7 @@ import org.slf4j.LoggerFactory; | ... | @@ -66,6 +67,7 @@ import org.slf4j.LoggerFactory; |
66 | 67 | ||
67 | import java.text.DecimalFormat; | 68 | import java.text.DecimalFormat; |
68 | import java.util.ArrayList; | 69 | import java.util.ArrayList; |
70 | +import java.util.Collection; | ||
69 | import java.util.Collections; | 71 | import java.util.Collections; |
70 | import java.util.HashMap; | 72 | import java.util.HashMap; |
71 | import java.util.HashSet; | 73 | import java.util.HashSet; |
... | @@ -82,6 +84,7 @@ import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_REMOVED; | ... | @@ -82,6 +84,7 @@ import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_REMOVED; |
82 | import static org.onlab.onos.cluster.ControllerNode.State.ACTIVE; | 84 | import static org.onlab.onos.cluster.ControllerNode.State.ACTIVE; |
83 | import static org.onlab.onos.net.DeviceId.deviceId; | 85 | import static org.onlab.onos.net.DeviceId.deviceId; |
84 | import static org.onlab.onos.net.HostId.hostId; | 86 | import static org.onlab.onos.net.HostId.hostId; |
87 | +import static org.onlab.onos.net.LinkKey.linkKey; | ||
85 | import static org.onlab.onos.net.PortNumber.P0; | 88 | import static org.onlab.onos.net.PortNumber.P0; |
86 | import static org.onlab.onos.net.PortNumber.portNumber; | 89 | import static org.onlab.onos.net.PortNumber.portNumber; |
87 | import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED; | 90 | import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED; |
... | @@ -110,8 +113,6 @@ public abstract class TopologyViewMessages { | ... | @@ -110,8 +113,6 @@ public abstract class TopologyViewMessages { |
110 | private static final String KB_UNIT = "KB"; | 113 | private static final String KB_UNIT = "KB"; |
111 | private static final String B_UNIT = "B"; | 114 | private static final String B_UNIT = "B"; |
112 | 115 | ||
113 | - private static final String ANIMATED = "animated"; | ||
114 | - | ||
115 | protected final ServiceDirectory directory; | 116 | protected final ServiceDirectory directory; |
116 | protected final ClusterService clusterService; | 117 | protected final ClusterService clusterService; |
117 | protected final DeviceService deviceService; | 118 | protected final DeviceService deviceService; |
... | @@ -560,14 +561,51 @@ public abstract class TopologyViewMessages { | ... | @@ -560,14 +561,51 @@ public abstract class TopologyViewMessages { |
560 | ObjectNode payload = mapper.createObjectNode(); | 561 | ObjectNode payload = mapper.createObjectNode(); |
561 | ArrayNode paths = mapper.createArrayNode(); | 562 | ArrayNode paths = mapper.createArrayNode(); |
562 | payload.set("paths", paths); | 563 | payload.set("paths", paths); |
563 | - for (Link link : linkService.getLinks()) { | 564 | + |
564 | - Set<Link> links = new HashSet<>(); | 565 | + ObjectNode pathNodeN = mapper.createObjectNode(); |
565 | - links.add(link); | 566 | + ArrayNode linksNodeN = mapper.createArrayNode(); |
566 | - addPathTraffic(paths, "plain", "secondary", links); | 567 | + ArrayNode labelsN = mapper.createArrayNode(); |
568 | + | ||
569 | + pathNodeN.put("class", "plain").put("traffic", false); | ||
570 | + pathNodeN.set("links", linksNodeN); | ||
571 | + pathNodeN.set("labels", labelsN); | ||
572 | + paths.add(pathNodeN); | ||
573 | + | ||
574 | + ObjectNode pathNodeT = mapper.createObjectNode(); | ||
575 | + ArrayNode linksNodeT = mapper.createArrayNode(); | ||
576 | + ArrayNode labelsT = mapper.createArrayNode(); | ||
577 | + | ||
578 | + pathNodeT.put("class", "secondary").put("traffic", true); | ||
579 | + pathNodeT.set("links", linksNodeT); | ||
580 | + pathNodeT.set("labels", labelsT); | ||
581 | + paths.add(pathNodeT); | ||
582 | + | ||
583 | + for (BiLink link : consolidateLinks(linkService.getLinks())) { | ||
584 | + boolean bi = link.two != null; | ||
585 | + if (isInfrastructureEgress(link.one) || | ||
586 | + (bi && isInfrastructureEgress(link.two))) { | ||
587 | + link.addLoad(statService.load(link.one)); | ||
588 | + link.addLoad(bi ? statService.load(link.two) : null); | ||
589 | + if (link.hasTraffic) { | ||
590 | + linksNodeT.add(compactLinkString(link.one)); | ||
591 | + labelsT.add(formatBytes(link.bytes)); | ||
592 | + } else { | ||
593 | + linksNodeN.add(compactLinkString(link.one)); | ||
594 | + labelsN.add(""); | ||
595 | + } | ||
596 | + } | ||
567 | } | 597 | } |
568 | return envelope("showTraffic", sid, payload); | 598 | return envelope("showTraffic", sid, payload); |
569 | } | 599 | } |
570 | 600 | ||
601 | + private Collection<BiLink> consolidateLinks(Iterable<Link> links) { | ||
602 | + Map<LinkKey, BiLink> biLinks = new HashMap<>(); | ||
603 | + for (Link link : links) { | ||
604 | + addLink(biLinks, link); | ||
605 | + } | ||
606 | + return biLinks.values(); | ||
607 | + } | ||
608 | + | ||
571 | // Produces JSON message to trigger flow overview visualization | 609 | // Produces JSON message to trigger flow overview visualization |
572 | protected ObjectNode flowSummaryMessage(long sid, Set<Device> devices) { | 610 | protected ObjectNode flowSummaryMessage(long sid, Set<Device> devices) { |
573 | ObjectNode payload = mapper.createObjectNode(); | 611 | ObjectNode payload = mapper.createObjectNode(); |
... | @@ -603,6 +641,33 @@ public abstract class TopologyViewMessages { | ... | @@ -603,6 +641,33 @@ public abstract class TopologyViewMessages { |
603 | ArrayNode paths = mapper.createArrayNode(); | 641 | ArrayNode paths = mapper.createArrayNode(); |
604 | payload.set("paths", paths); | 642 | payload.set("paths", paths); |
605 | 643 | ||
644 | + // Classify links based on their traffic traffic first... | ||
645 | + Map<LinkKey, BiLink> biLinks = classifyLinkTraffic(trafficClasses); | ||
646 | + | ||
647 | + // Then separate the links into their respective classes and send them out. | ||
648 | + Map<String, ObjectNode> pathNodes = new HashMap<>(); | ||
649 | + for (BiLink biLink : biLinks.values()) { | ||
650 | + boolean hasTraffic = biLink.hasTraffic; | ||
651 | + String tc = (biLink.classes + (hasTraffic ? " animated" : "")).trim(); | ||
652 | + ObjectNode pathNode = pathNodes.get(tc); | ||
653 | + if (pathNode == null) { | ||
654 | + pathNode = mapper.createObjectNode() | ||
655 | + .put("class", tc).put("traffic", hasTraffic); | ||
656 | + pathNode.set("links", mapper.createArrayNode()); | ||
657 | + pathNode.set("labels", mapper.createArrayNode()); | ||
658 | + pathNodes.put(tc, pathNode); | ||
659 | + paths.add(pathNode); | ||
660 | + } | ||
661 | + ((ArrayNode) pathNode.path("links")).add(compactLinkString(biLink.one)); | ||
662 | + ((ArrayNode) pathNode.path("labels")).add(hasTraffic ? formatBytes(biLink.bytes) : ""); | ||
663 | + } | ||
664 | + | ||
665 | + return envelope("showTraffic", sid, payload); | ||
666 | + } | ||
667 | + | ||
668 | + // Classifies the link traffic according to the specified classes. | ||
669 | + private Map<LinkKey, BiLink> classifyLinkTraffic(TrafficClass... trafficClasses) { | ||
670 | + Map<LinkKey, BiLink> biLinks = new HashMap<>(); | ||
606 | for (TrafficClass trafficClass : trafficClasses) { | 671 | for (TrafficClass trafficClass : trafficClasses) { |
607 | for (Intent intent : trafficClass.intents) { | 672 | for (Intent intent : trafficClass.intents) { |
608 | boolean isOptical = intent instanceof OpticalConnectivityIntent; | 673 | boolean isOptical = intent instanceof OpticalConnectivityIntent; |
... | @@ -611,24 +676,49 @@ public abstract class TopologyViewMessages { | ... | @@ -611,24 +676,49 @@ public abstract class TopologyViewMessages { |
611 | for (Intent installable : installables) { | 676 | for (Intent installable : installables) { |
612 | String cls = isOptical ? trafficClass.type + " optical" : trafficClass.type; | 677 | String cls = isOptical ? trafficClass.type + " optical" : trafficClass.type; |
613 | if (installable instanceof PathIntent) { | 678 | if (installable instanceof PathIntent) { |
614 | - addPathTraffic(paths, cls, ANIMATED, | 679 | + classifyLinks(cls, biLinks, ((PathIntent) installable).path().links()); |
615 | - ((PathIntent) installable).path().links()); | ||
616 | } else if (installable instanceof LinkCollectionIntent) { | 680 | } else if (installable instanceof LinkCollectionIntent) { |
617 | - addPathTraffic(paths, cls, ANIMATED, | 681 | + classifyLinks(cls, biLinks, ((LinkCollectionIntent) installable).links()); |
618 | - ((LinkCollectionIntent) installable).links()); | ||
619 | } else if (installable instanceof OpticalPathIntent) { | 682 | } else if (installable instanceof OpticalPathIntent) { |
620 | - addPathTraffic(paths, cls, ANIMATED, | 683 | + classifyLinks(cls, biLinks, ((OpticalPathIntent) installable).path().links()); |
621 | - ((OpticalPathIntent) installable).path().links()); | ||
622 | } | 684 | } |
623 | - | ||
624 | } | 685 | } |
625 | } | 686 | } |
626 | } | 687 | } |
627 | } | 688 | } |
689 | + return biLinks; | ||
690 | + } | ||
628 | 691 | ||
629 | - return envelope("showTraffic", sid, payload); | 692 | + |
693 | + // Adds the link segments (path or tree) associated with the specified | ||
694 | + // connectivity intent | ||
695 | + private void classifyLinks(String type, Map<LinkKey, BiLink> biLinks, | ||
696 | + Iterable<Link> links) { | ||
697 | + if (links != null) { | ||
698 | + for (Link link : links) { | ||
699 | + BiLink biLink = addLink(biLinks, link); | ||
700 | + if (isInfrastructureEgress(link)) { | ||
701 | + biLink.addLoad(statService.load(link)); | ||
702 | + biLink.addClass(type); | ||
703 | + } | ||
704 | + } | ||
705 | + } | ||
706 | + } | ||
707 | + | ||
708 | + | ||
709 | + private BiLink addLink(Map<LinkKey, BiLink> biLinks, Link link) { | ||
710 | + LinkKey key = canonicalLinkKey(link); | ||
711 | + BiLink biLink = biLinks.get(key); | ||
712 | + if (biLink != null) { | ||
713 | + biLink.setOther(link); | ||
714 | + } else { | ||
715 | + biLink = new BiLink(key, link); | ||
716 | + biLinks.put(key, biLink); | ||
717 | + } | ||
718 | + return biLink; | ||
630 | } | 719 | } |
631 | 720 | ||
721 | + | ||
632 | // Adds the link segments (path or tree) associated with the specified | 722 | // Adds the link segments (path or tree) associated with the specified |
633 | // connectivity intent | 723 | // connectivity intent |
634 | protected void addPathTraffic(ArrayNode paths, String type, String trafficType, | 724 | protected void addPathTraffic(ArrayNode paths, String type, String trafficType, |
... | @@ -646,7 +736,7 @@ public abstract class TopologyViewMessages { | ... | @@ -646,7 +736,7 @@ public abstract class TopologyViewMessages { |
646 | String label = ""; | 736 | String label = ""; |
647 | if (load.rate() > 0) { | 737 | if (load.rate() > 0) { |
648 | hasTraffic = true; | 738 | hasTraffic = true; |
649 | - label = format(load); | 739 | + label = formatBytes(load.latest()); |
650 | } | 740 | } |
651 | labels.add(label); | 741 | labels.add(label); |
652 | } | 742 | } |
... | @@ -660,8 +750,7 @@ public abstract class TopologyViewMessages { | ... | @@ -660,8 +750,7 @@ public abstract class TopologyViewMessages { |
660 | } | 750 | } |
661 | 751 | ||
662 | // Poor-mans formatting to get the labels with byte counts looking nice. | 752 | // Poor-mans formatting to get the labels with byte counts looking nice. |
663 | - private String format(Load load) { | 753 | + private String formatBytes(long bytes) { |
664 | - long bytes = load.latest(); | ||
665 | String unit; | 754 | String unit; |
666 | double value; | 755 | double value; |
667 | if (bytes > GB) { | 756 | if (bytes > GB) { |
... | @@ -713,6 +802,44 @@ public abstract class TopologyViewMessages { | ... | @@ -713,6 +802,44 @@ public abstract class TopologyViewMessages { |
713 | return result; | 802 | return result; |
714 | } | 803 | } |
715 | 804 | ||
805 | + // Produces canonical link key, i.e. one that will match link and its inverse. | ||
806 | + private LinkKey canonicalLinkKey(Link link) { | ||
807 | + String sn = link.src().elementId().toString(); | ||
808 | + String dn = link.dst().elementId().toString(); | ||
809 | + return sn.compareTo(dn) < 0 ? | ||
810 | + linkKey(link.src(), link.dst()) : linkKey(link.dst(), link.src()); | ||
811 | + } | ||
812 | + | ||
813 | + // Representation of link and its inverse and any traffic data. | ||
814 | + private class BiLink { | ||
815 | + public final LinkKey key; | ||
816 | + public final Link one; | ||
817 | + public Link two; | ||
818 | + public boolean hasTraffic = false; | ||
819 | + public long bytes = 0; | ||
820 | + public String classes = ""; | ||
821 | + | ||
822 | + BiLink(LinkKey key, Link link) { | ||
823 | + this.key = key; | ||
824 | + this.one = link; | ||
825 | + } | ||
826 | + | ||
827 | + void setOther(Link link) { | ||
828 | + this.two = link; | ||
829 | + } | ||
830 | + | ||
831 | + void addLoad(Load load) { | ||
832 | + if (load != null) { | ||
833 | + this.hasTraffic = hasTraffic || load.rate() > 0; | ||
834 | + this.bytes += load.latest(); | ||
835 | + } | ||
836 | + } | ||
837 | + | ||
838 | + void addClass(String trafficClass) { | ||
839 | + classes = classes + " " + trafficClass; | ||
840 | + } | ||
841 | + } | ||
842 | + | ||
716 | // Auxiliary key/value carrier. | 843 | // Auxiliary key/value carrier. |
717 | private class Prop { | 844 | private class Prop { |
718 | public final String key; | 845 | public final String key; | ... | ... |
... | @@ -558,7 +558,7 @@ public class TopologyViewWebSocket | ... | @@ -558,7 +558,7 @@ public class TopologyViewWebSocket |
558 | } | 558 | } |
559 | } | 559 | } |
560 | 560 | ||
561 | - // Accummulates events to drive methodic update of the summary pane. | 561 | + // Accumulates events to drive methodic update of the summary pane. |
562 | private class InternalEventAccummulator extends AbstractEventAccumulator { | 562 | private class InternalEventAccummulator extends AbstractEventAccumulator { |
563 | protected InternalEventAccummulator() { | 563 | protected InternalEventAccummulator() { |
564 | super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS); | 564 | super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS); | ... | ... |
-
Please register or login to post a comment