[SDFAB-705] Fix GUI for the control and data plane resiliency
Additionally, fix similar issues in GUI2 and add initial
support for ports with name in GUI/GUI2.
This is also the first step towards supporting port with name widely in ONOS
Change-Id: Ib04f780bf0b7171e82a6beb69b39c0aaeb4be957
(cherry picked from commit 178046ba11ab21d94a1e818fb893931bb015734b)
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java b/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java
index 311d44f..92a051c 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/PortViewMessageHandler.java
@@ -131,7 +131,7 @@
}
private void populateRow(TableModel.Row row, PortStatistics stat) {
- row.cell(ID, stat.portNumber().toLong())
+ row.cell(ID, stat.portNumber())
.cell(PKT_RX, stat.packetsReceived())
.cell(PKT_TX, stat.packetsSent())
.cell(BYTES_RX, stat.bytesReceived())
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 02bc1ff..776ea58 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
@@ -81,7 +81,7 @@
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
-import static org.onosproject.net.ConnectPoint.deviceConnectPoint;
+import static org.onosproject.net.ConnectPoint.fromString;
import static org.onosproject.net.DeviceId.deviceId;
import static org.onosproject.net.HostId.hostId;
import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
@@ -394,7 +394,7 @@
if (isEdgeLink) {
HostId hid = hostId(srcId);
String cpstr = tgtId + SLASH + string(payload, TARGET_PORT);
- ConnectPoint cp = deviceConnectPoint(cpstr);
+ ConnectPoint cp = fromString(cpstr);
pp = edgeLinkDetails(hid, cp);
overlayCache.currentOverlay().modifyEdgeLinkDetails(pp, hid, cp);
@@ -402,8 +402,8 @@
} else {
String cpAstr = srcId + SLASH + string(payload, SOURCE_PORT);
String cpBstr = tgtId + SLASH + string(payload, TARGET_PORT);
- ConnectPoint cpA = deviceConnectPoint(cpAstr);
- ConnectPoint cpB = deviceConnectPoint(cpBstr);
+ ConnectPoint cpA = fromString(cpAstr);
+ ConnectPoint cpB = fromString(cpBstr);
pp = infraLinkDetails(cpA, cpB);
overlayCache.currentOverlay().modifyInfraLinkDetails(pp, cpA, cpB);
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 ff52584..3bd4985 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
@@ -377,7 +377,7 @@
private ObjectNode hostConnect(HostLocation location) {
return objectNode()
.put("device", location.deviceId().toString())
- .put("port", location.port().toLong());
+ .put("port", location.port().toString());
}
// Encodes the specified list of labels a JSON array.
@@ -639,7 +639,7 @@
pp.addProp(LPL_A_TYPE, lion.getSafe(LPL_A_TYPE), lion.getSafe(DEVICE))
.addProp(LPL_A_ID, lion.getSafe(LPL_A_ID), did.toString())
.addProp(LPL_A_FRIENDLY, lion.getSafe(LPL_A_FRIENDLY), friendlyDevice(did))
- .addProp(LPL_A_PORT, lion.getSafe(LPL_A_PORT), cp.port().toLong())
+ .addProp(LPL_A_PORT, lion.getSafe(LPL_A_PORT), cp.port().toString())
.addSeparator();
}
@@ -649,7 +649,7 @@
pp.addProp(LPL_B_TYPE, lion.getSafe(LPL_B_TYPE), lion.getSafe(DEVICE))
.addProp(LPL_B_ID, lion.getSafe(LPL_B_ID), did.toString())
.addProp(LPL_B_FRIENDLY, lion.getSafe(LPL_B_FRIENDLY), friendlyDevice(did))
- .addProp(LPL_B_PORT, lion.getSafe(LPL_B_PORT), cp.port().toLong())
+ .addProp(LPL_B_PORT, lion.getSafe(LPL_B_PORT), cp.port().toString())
.addSeparator();
}
diff --git a/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.spec.ts b/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.spec.ts
index 5ebc0d6..96142af 100644
--- a/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.spec.ts
+++ b/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.spec.ts
@@ -30,7 +30,7 @@
import {SubRegionNodeSvgComponent} from './visuals/subregionnodesvg/subregionnodesvg.component';
import {HostNodeSvgComponent} from './visuals/hostnodesvg/hostnodesvg.component';
import {LinkSvgComponent} from './visuals/linksvg/linksvg.component';
-import {Device, Host, Link, LinkType, LinkHighlight, Region} from './models';
+import {Device, Host, Link, LinkType, LinkHighlight, Region, Node} from './models';
import {ChangeDetectorRef, SimpleChange} from '@angular/core';
import {TopologyService} from '../../topology.service';
import {BadgeSvgComponent} from './visuals/badgesvg/badgesvg.component';
@@ -1413,6 +1413,122 @@
"subregions": [],
"links": [
{
+ "id": "00:00:00:00:00:22/120~device:leaf4/[3/0](3)",
+ "epA": "00:00:00:00:00:22/120",
+ "epB": "device:leaf4",
+ "type": "UiEdgeLink",
+ "portB": "[3/0](3)",
+ "rollup": [
+ {
+ "id": "00:00:00:00:00:22/120~device:leaf4/[3/0](3)",
+ "epA": "00:00:00:00:00:22/120",
+ "epB": "device:leaf4",
+ "type": "UiEdgeLink",
+ "portB": "[3/0](3)"
+ }
+ ]
+ },
+ {
+ "id": "00:00:00:00:00:1E/None~device:leaf4/[2/0](2)",
+ "epA": "00:00:00:00:00:1E/None",
+ "epB": "device:leaf4",
+ "type": "UiEdgeLink",
+ "portB": "[2/0](2)",
+ "rollup": [
+ {
+ "id": "00:00:00:00:00:1E/None~device:leaf4/[2/0](2)",
+ "epA": "00:00:00:00:00:1E/None",
+ "epB": "device:leaf4",
+ "type": "UiEdgeLink",
+ "portB": "[2/0](2)"
+ }
+ ]
+ },
+ {
+ "id": "device:leaf4/[1/0](1)~device:spine1/[3/0](3)",
+ "epA": "device:leaf4/[1/0](1)",
+ "epB": "device:spine1/[3/0](3)",
+ "type": "UiDeviceLink",
+ "portA": "[1/0](1)",
+ "portB": "[3/0](3)",
+ "rollup": [
+ {
+ "id": "device:leaf4/[1/0](1)~device:spine1/[3/0](3)",
+ "epA": "device:leaf4/[1/0](1)",
+ "epB": "device:spine1/[3/0](3)",
+ "type": "UiDeviceLink",
+ "portA": "[1/0](1)",
+ "portB": "[3/0](3)"
+ }
+ ]
+ },
+ {
+ "id": "00:00:00:00:00:21/120~device:leaf3/[leaf3-eth3](3)",
+ "epA": "00:00:00:00:00:21/120",
+ "epB": "device:leaf3",
+ "type": "UiEdgeLink",
+ "portB": "[leaf3-eth3](3)",
+ "rollup": [
+ {
+ "id": "00:00:00:00:00:21/120~device:leaf3/[leaf3-eth3](3)",
+ "epA": "00:00:00:00:00:21/120",
+ "epB": "device:leaf3",
+ "type": "UiEdgeLink",
+ "portB": "[leaf3-eth3](3)"
+ }
+ ]
+ },
+ {
+ "id": "00:00:00:00:00:1D/None~device:leaf3/[leaf3-eth2](2)",
+ "epA": "00:00:00:00:00:1D/None",
+ "epB": "device:leaf3",
+ "type": "UiEdgeLink",
+ "portB": "[leaf3-eth2](2)",
+ "rollup": [
+ {
+ "id": "00:00:00:00:00:1D/None~device:leaf3/[leaf3-eth2](2)",
+ "epA": "00:00:00:00:00:1D/None",
+ "epB": "device:leaf3",
+ "type": "UiEdgeLink",
+ "portB": "[leaf3-eth2](2)"
+ }
+ ]
+ },
+ {
+ "id": "device:leaf3/[leaf3-eth1](1)~device:spine1/[spine1-eth3](3)",
+ "epA": "device:leaf3/[leaf3-eth1](1)",
+ "epB": "device:spine1/[spine1-eth3](3)",
+ "type": "UiDeviceLink",
+ "portA": "[leaf3-eth1](1)",
+ "portB": "[spine1-eth3](3)",
+ "rollup": [
+ {
+ "id": "device:leaf3/[leaf3-eth1](1)~device:spine1/[spine1-eth3](3)",
+ "epA": "device:leaf3/[leaf3-eth1](1)",
+ "epB": "device:spine1/[spine1-eth3](3)",
+ "type": "UiDeviceLink",
+ "portA": "[leaf3-eth1](1)",
+ "portB": "[spine1-eth3](3)"
+ }
+ ]
+ },
+ {
+ "id": "00:00:00:00:00:1F/120~device:leaf1/7",
+ "epA": "00:00:00:00:00:1F/120",
+ "epB": "device:leaf1",
+ "type": "UiEdgeLink",
+ "portB": "7",
+ "rollup": [
+ {
+ "id": "00:00:00:00:00:1F/120~device:leaf1/7",
+ "epA": "00:00:00:00:00:1F/120",
+ "epB": "device:leaf1",
+ "type": "UiEdgeLink",
+ "portB": "7"
+ }
+ ]
+ },
+ {
"id": "device:leaf1/1~device:spine1/1",
"epA": "device:leaf1/1",
"epB": "device:spine1/1",
@@ -1570,6 +1686,52 @@
[],
[
{
+ "id": "device:leaf4",
+ "nodeType": "device",
+ "type": "switch",
+ "online": true,
+ "master": "172.24.0.3",
+ "layer": "def",
+ "props": {
+ "managementAddress": "grpc://pippo:50003?device_id=1",
+ "protocol": "P4Runtime, gNMI, gNOI",
+ "gridX": "400.0",
+ "gridY": "400.0",
+ "driver": "stratum-tofino",
+ "name": "device:leaf4",
+ "p4DeviceId": "1",
+ "locType": "grid"
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 400.0,
+ "longOrX": 400.0
+ }
+ },
+ {
+ "id": "device:leaf3",
+ "nodeType": "device",
+ "type": "switch",
+ "online": true,
+ "master": "172.24.0.3",
+ "layer": "def",
+ "props": {
+ "managementAddress": "grpc://mininet:50003?device_id=1",
+ "protocol": "P4Runtime, gNMI, gNOI",
+ "gridX": "400.0",
+ "gridY": "400.0",
+ "driver": "stratum-bmv2",
+ "name": "device:leaf3",
+ "p4DeviceId": "1",
+ "locType": "grid"
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 400.0,
+ "longOrX": 400.0
+ }
+ },
+ {
"id": "device:spine1",
"nodeType": "device",
"type": "switch",
@@ -1668,6 +1830,116 @@
[],
[
{
+ "id": "00:00:00:00:00:22/120",
+ "nodeType": "host",
+ "layer": "def",
+ "ips": [
+ "2001:2:3::1"
+ ],
+ "props": {
+ "gridX": "750.0",
+ "gridY": "700.0",
+ "latitude": null,
+ "name": "h3",
+ "locType": "grid",
+ "longitude": null
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 700.0,
+ "longOrX": 750.0
+ },
+ "configured": false
+ },
+ {
+ "id": "00:00:00:00:00:21/120",
+ "nodeType": "host",
+ "layer": "def",
+ "ips": [
+ "2001:2:3::1"
+ ],
+ "props": {
+ "gridX": "750.0",
+ "gridY": "700.0",
+ "latitude": null,
+ "name": "h3",
+ "locType": "grid",
+ "longitude": null
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 700.0,
+ "longOrX": 750.0
+ },
+ "configured": false
+ },
+ {
+ "id": "00:00:00:00:00:1F/120",
+ "nodeType": "host",
+ "layer": "def",
+ "ips": [
+ "2001:2:3::1"
+ ],
+ "props": {
+ "gridX": "750.0",
+ "gridY": "700.0",
+ "latitude": null,
+ "name": "h3",
+ "locType": "grid",
+ "longitude": null
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 700.0,
+ "longOrX": 750.0
+ },
+ "configured": false
+ },
+ {
+ "id": "00:00:00:00:00:1E/None",
+ "nodeType": "host",
+ "layer": "def",
+ "ips": [
+ "2001:2:3::1"
+ ],
+ "props": {
+ "gridX": "750.0",
+ "gridY": "700.0",
+ "latitude": null,
+ "name": "h3",
+ "locType": "grid",
+ "longitude": null
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 700.0,
+ "longOrX": 750.0
+ },
+ "configured": false
+ },
+ {
+ "id": "00:00:00:00:00:1D/None",
+ "nodeType": "host",
+ "layer": "def",
+ "ips": [
+ "2001:2:3::1"
+ ],
+ "props": {
+ "gridX": "750.0",
+ "gridY": "700.0",
+ "latitude": null,
+ "name": "h3",
+ "locType": "grid",
+ "longitude": null
+ },
+ "location": {
+ "locType": "grid",
+ "latOrY": 700.0,
+ "longOrX": 750.0
+ },
+ "configured": false
+ },
+ {
"id": "00:00:00:00:00:30/None",
"nodeType": "host",
"layer": "def",
@@ -1795,6 +2067,41 @@
"hosts": [],
"links": [
{
+ "id": "00:00:00:00:00:22/120~device:leaf4/[3/0](3)",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
+ "id": "00:00:00:00:00:1E/None~device:leaf4/[2/0](2)",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
+ "id": "device:leaf4/[1/0](1)~device:spine1/[3/0](3)",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
+ "id": "00:00:00:00:00:21/120~device:leaf3/[leaf3-eth3](3)",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
+ "id": "00:00:00:00:00:1D/None~device:leaf3/[leaf3-eth2](2)",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
+ "id": "device:leaf3/[leaf3-eth1](1)~device:spine1/[spine1-eth3](3)",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
+ "id": "00:00:00:00:00:1F/120~device:leaf1/7",
+ "label": "964.91 Kbps",
+ "css": "secondary port-traffic-green"
+ },
+ {
"id": "device:leaf2/2~device:spine2/2",
"label": "964.91 Kbps",
"css": "secondary port-traffic-green"
@@ -1828,6 +2135,16 @@
}
}`;
+const topo2Highlights_sample2 = `
+{
+ "event": "topo2Highlights",
+ "payload": {
+ "devices": [],
+ "hosts": [],
+ "links": []
+ }
+}`;
+
class MockActivatedRoute extends ActivatedRoute {
constructor(params: Params) {
super();
@@ -2071,6 +2388,23 @@
// Like epB of second example in sampleData file - endPtStr does not contain port number
expect(ForceSvgComponent.extractNodeName('of:0000000000000206', '6'))
.toEqual('of:0000000000000206');
+
+ // bmv2 case - no port in the endpoint
+ expect(ForceSvgComponent.extractNodeName('device:leaf1', '[leaf1-eth1](1)'))
+ .toEqual('device:leaf1');
+
+ // bmv2 case - port in the endpoint
+ expect(ForceSvgComponent.extractNodeName('device:leaf1/[leaf1-eth1](1)', '[leaf1-eth1](1)'))
+ .toEqual('device:leaf1');
+
+ // tofino case - no port in the endpoint
+ expect(ForceSvgComponent.extractNodeName('device:leaf1', '[1/0](1)'))
+ .toEqual('device:leaf1');
+
+ // tofino case - port in the endpoint
+ expect(ForceSvgComponent.extractNodeName('device:leaf1/[1/0](1)', '[1/0](1)'))
+ .toEqual('device:leaf1');
+
});
it('should handle openflow regionData change - sample Region', () => {
@@ -2100,9 +2434,23 @@
component.ngOnChanges(
{'regionData' : new SimpleChange(<Region>{}, topo2BaseRegionData, true)});
- expect(component.graph.links.length).toBe(9);
+ expect(component.graph.links.length).toBe(16);
+ expect(component.graph.nodes.length).toBe(16)
+ expect(linkHightlights.length).toBe(13);
- expect(linkHightlights.length).toBe(6);
+ // sanitize deviceNameFromEp
+ component.graph.links.forEach((l: Link) => {
+ if (<LinkType><unknown>LinkType[l.type] === LinkType.UiEdgeLink) {
+ // edge link has only one epoint valid (the other is not deviceId)
+ const foundNode = component.graph.nodes.find((n: Node) => n.id === Link.deviceNameFromEp(l.epB));
+ expect(foundNode).toBeDefined();
+ } else {
+ var foundNode = component.graph.nodes.find((n: Node) => n.id === Link.deviceNameFromEp(l.epA));
+ expect(foundNode).toBeDefined();
+ foundNode = component.graph.nodes.find((n: Node) => n.id === Link.deviceNameFromEp(l.epB));
+ expect(foundNode).toBeDefined();
+ }
+ });
// should be able to find all of the highlighted links in the original data set
linkHightlights.forEach((lh: LinkHighlight) => {
diff --git a/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.ts b/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.ts
index dc67bc2..234f1e9 100644
--- a/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.ts
+++ b/web/gui2-topo-lib/lib/layer/forcesvg/forcesvg.component.ts
@@ -123,6 +123,7 @@
* In some cases - have to remove the port number from the end of a device
* name
* @param endPtStr The end point name
+ * @param portStr The port name
*/
static extractNodeName(endPtStr: string, portStr: string): string {
if (portStr === undefined || endPtStr === undefined) {
diff --git a/web/gui2-topo-lib/lib/layer/forcesvg/models/link.ts b/web/gui2-topo-lib/lib/layer/forcesvg/models/link.ts
index d5ff2a7..f3b839c 100644
--- a/web/gui2-topo-lib/lib/layer/forcesvg/models/link.ts
+++ b/web/gui2-topo-lib/lib/layer/forcesvg/models/link.ts
@@ -55,7 +55,12 @@
public static deviceNameFromEp(ep: string): string {
if (ep !== undefined && ep.lastIndexOf('/') > 0) {
- return ep.substr(0, ep.lastIndexOf('/'));
+ // named port format is [name](number)
+ if (ep.includes('[')) {
+ return ep.substr(0, ep.lastIndexOf('[') - 1);
+ } else {
+ return ep.substr(0, ep.lastIndexOf('/'));
+ }
}
return ep;
}
@@ -66,17 +71,47 @@
* @param linkId The id of the link in either format
*/
public static linkIdFromShowHighlights(linkId: string) {
- if (linkId.includes('-')) {
- const parts: string[] = linkId.split('-');
+ // Already in the right format
+ if (linkId.includes('~')) {
+ const parts: string[] = linkId.split('~');
+ // remove host part if needed
const part0 = Link.removeHostPortNum(parts[0]);
const part1 = Link.removeHostPortNum(parts[1]);
return part0 + '~' + part1;
}
+
+ // Custom traffic highlight
+ if (linkId.includes('-')) {
+ // "-" is used only as separator between the links
+ if (linkId.indexOf('-') === linkId.lastIndexOf('-')) {
+ const parts: string[] = linkId.split('-');
+ const part0 = Link.removeHostPortNum(parts[0]);
+ const part1 = Link.removeHostPortNum(parts[1]);
+ return part0 + '~' + part1;
+ } else if (linkId.includes(')')) {
+ // "-" is used in the port name
+ var index = linkId.indexOf(')');
+ // the format is [name](number) on both ends
+ if (linkId.charAt(index + 1) === '-') {
+ const part0 = Link.removeHostPortNum(linkId.substr(0, index + 1));
+ const part1 = Link.removeHostPortNum(linkId.substr(index + 2, linkId.length));
+ return part0 + '~' + part1;
+ } else {
+ index = linkId.indexOf('-');
+ const part0 = Link.removeHostPortNum(linkId.substr(0, index));
+ const part1 = Link.removeHostPortNum(linkId.substr(index + 1, linkId.length));
+ return part0 + '~' + part1;
+ }
+ }
+ }
+
+ // unknown format
return linkId;
}
private static removeHostPortNum(hostStr: string) {
- if (hostStr.includes('/None/')) {
+ // Regex is for the tagged hosts
+ if (hostStr.includes('/None/') || hostStr.match('/[+-]?[0-9]+/')) {
const subparts = hostStr.split('/');
return subparts[0] + '/' + subparts[1];
}