Adding enhancements to the GUI server-side.
Fixing a few intent-related glitches for the optical use-case.
Fixing lat/lng information in the optical config.
Change-Id: I6a1dd1ee69c2db2f0e351d191627bba468a3c49c
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java
index 13f3000..c137b9a 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java
@@ -15,8 +15,6 @@
*/
package org.onlab.onos.cli.net;
-import java.util.List;
-
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onlab.onos.net.HostId;
@@ -28,6 +26,8 @@
import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.IntentService;
+import java.util.List;
+
/**
* Installs host-to-host connectivity intent.
*/
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
index 5c513e3..56d9de3 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
@@ -20,11 +20,13 @@
import org.apache.karaf.shell.commands.Option;
import org.onlab.onos.cli.AbstractShellCommand;
+import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.DefaultTrafficSelector;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.intent.Constraint;
import org.onlab.onos.net.intent.constraint.BandwidthConstraint;
import org.onlab.onos.net.intent.constraint.LambdaConstraint;
+import org.onlab.onos.net.intent.constraint.LinkTypeConstraint;
import org.onlab.onos.net.resource.Bandwidth;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpPrefix;
@@ -142,6 +144,7 @@
if (lambda) {
constraints.add(new LambdaConstraint(null));
}
+ constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL));
return constraints;
}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
index 24a3bca..e09767a 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
@@ -16,12 +16,14 @@
package org.onlab.onos.net.intent;
import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.HostId;
+import org.onlab.onos.net.Link;
import org.onlab.onos.net.flow.TrafficSelector;
import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.intent.constraint.LinkTypeConstraint;
-import java.util.Collections;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -47,7 +49,8 @@
public HostToHostIntent(ApplicationId appId, HostId one, HostId two,
TrafficSelector selector,
TrafficTreatment treatment) {
- this(appId, one, two, selector, treatment, Collections.emptyList());
+ this(appId, one, two, selector, treatment,
+ ImmutableList.of(new LinkTypeConstraint(false, Link.Type.OPTICAL)));
}
/**
diff --git a/tools/test/topos/oe-linear-3.json b/tools/test/topos/oe-linear-3.json
index 728b472..f35cc98 100644
--- a/tools/test/topos/oe-linear-3.json
+++ b/tools/test/topos/oe-linear-3.json
@@ -3,32 +3,32 @@
{
"uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM1",
- "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 },
+ "annotations": { "latitude": 37.6, "longitude": -122.3, "optical.regens": 0 },
"ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM2",
- "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 },
+ "annotations": { "latitude": 37.3, "longitude": -121.9, "optical.regens": 0 },
"ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM3",
- "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 },
+ "annotations": { "latitude": 33.9, "longitude": -118.4, "optical.regens": 2 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER1",
- "annotations": { "latitude": 37.6, "longitude": 122.3 },
+ "annotations": { "latitude": 37.6, "longitude": -122.3 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER2",
- "annotations": { "latitude": 37.3, "longitude": 121.9 },
+ "annotations": { "latitude": 37.3, "longitude": -121.9 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
}
],
diff --git a/tools/test/topos/oe-nonlinear-10.json b/tools/test/topos/oe-nonlinear-10.json
index 29086bb..3a48417 100644
--- a/tools/test/topos/oe-nonlinear-10.json
+++ b/tools/test/topos/oe-nonlinear-10.json
@@ -3,7 +3,7 @@
{
"uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SFO-W10",
- "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 },
+ "annotations": { "latitude": 37.6, "longitude": -122.3, "optical.regens": 0 },
"ports": [ { "port": 10, "speed": 100000, "type": "FIBER" },
{ "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 50, "speed":100000, "type": "FIBER" } ]
@@ -11,7 +11,7 @@
{
"uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SJC-W10",
- "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 },
+ "annotations": { "latitude": 37.3, "longitude": -121.9, "optical.regens": 0 },
"ports": [ { "port": 20, "speed": 100000, "type": "FIBER" },
{ "port": 30, "speed": 0, "type": "FIBER" },
{ "port": 50, "speed": 0, "type": "FIBER" } ]
@@ -19,7 +19,7 @@
{
"uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "LAX-W10",
- "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 0 },
+ "annotations": { "latitude": 33.9, "longitude": -118.4, "optical.regens": 0 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" },
{ "port": 50, "speed": 0, "type": "FIBER" },
{ "port": 20, "speed": 0, "type": "FIBER" } ]
@@ -27,7 +27,7 @@
{
"uri": "of:0000ffffffffff04", "mac": "ffffffffffff04", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "SDG-W10",
- "annotations": { "latitude": 32.8, "longitude": 117.1, "optical.regens": 3 },
+ "annotations": { "latitude": 32.8, "longitude": -117.1, "optical.regens": 3 },
"ports": [ { "port": 30, "speed": 0, "type": "FIBER" },
{ "port":50, "speed": 0, "type": "FIBER" },
{ "port":20, "speed": 0, "type": "FIBER" }]
@@ -35,7 +35,7 @@
{
"uri": "of:0000ffffffffff05", "mac": "ffffffffffff05", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "MSP-M10",
- "annotations": { "latitude": 44.8, "longitude": 93.1, "optical.regens": 3 },
+ "annotations": { "latitude": 44.8, "longitude": -93.1, "optical.regens": 3 },
"ports": [ { "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 30, "speed": 0, "type": "FIBER" },
{ "port": 40, "speed": 0, "type": "FIBER" },
@@ -44,7 +44,7 @@
{
"uri": "of:0000ffffffffff06", "mac": "ffffffffffff06", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "DFW-M10",
- "annotations": { "latitude": 32.8, "longitude": 97.1, "optical.regens": 3 },
+ "annotations": { "latitude": 32.8, "longitude": -97.1, "optical.regens": 3 },
"ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
{ "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 30, "speed": 0, "type": "FIBER" },
@@ -54,7 +54,7 @@
{
"uri": "of:0000ffffffffff07", "mac": "ffffffffffff07", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "CHG-N10",
- "annotations": { "latitude": 41.8, "longitude": 120.1, "optical.regens": 3 },
+ "annotations": { "latitude": 41.8, "longitude": -120.1, "optical.regens": 3 },
"ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
{ "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 30, "speed": 0, "type": "FIBER" },
@@ -63,7 +63,7 @@
{
"uri": "of:0000ffffffffff08", "mac": "ffffffffffff08", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "IAD-M10",
- "annotations": { "latitude": 38.8, "longitude": 77.1, "optical.regens": 3 },
+ "annotations": { "latitude": 38.8, "longitude": -77.1, "optical.regens": 3 },
"ports": [ { "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 30, "speed": 0, "type": "FIBER" },
{ "port": 50, "speed": 0, "type": "FIBER" }]
@@ -71,7 +71,7 @@
{
"uri": "of:0000ffffffffff09", "mac": "ffffffffffff09", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "JFK-M10",
- "annotations": { "latitude": 40.8, "longitude": 73.1, "optical.regens": 0 },
+ "annotations": { "latitude": 40.8, "longitude": -73.1, "optical.regens": 0 },
"ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
{ "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 50, "speed": 0, "type": "FIBER" }]
@@ -79,7 +79,7 @@
{
"uri": "of:0000ffffffffff0A", "mac": "ffffffffffff0A", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ATL-S10",
- "annotations": { "latitude": 33.8, "longitude": 84.1, "optical.regens": 0 },
+ "annotations": { "latitude": 33.8, "longitude": -84.1, "optical.regens": 0 },
"ports": [ { "port": 10, "speed": 0, "type": "FIBER" },
{ "port": 20, "speed": 0, "type": "FIBER" },
{ "port": 50, "speed": 0, "type": "FIBER" }]
@@ -87,37 +87,37 @@
{
"uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "SFO-R10",
- "annotations": { "latitude": 37.6, "longitude": 122.3 },
+ "annotations": { "latitude": 37.6, "longitude": -122.3 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0002", "mac": "ffffffffff0003", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "LAX-R10",
- "annotations": { "latitude": 33.9, "longitude": 118.4 },
+ "annotations": { "latitude": 33.9, "longitude": -118.4 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0003", "mac": "ffffffffff0004", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "SDG-R10",
- "annotations": { "latitude": 32.8, "longitude": 117.1 },
+ "annotations": { "latitude": 32.8, "longitude": -117.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0004", "mac": "ffffffffff0007", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "CHG-R10",
- "annotations": { "latitude": 41.8, "longitude": 120.1 },
+ "annotations": { "latitude": 41.8, "longitude": -120.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0005", "mac": "ffffffffff0009", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "JFK-R10",
- "annotations": { "latitude": 40.8, "longitude": 73.1 },
+ "annotations": { "latitude": 40.8, "longitude": -73.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0006", "mac": "ffffffffff000A", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ATL-R10",
- "annotations": { "latitude": 33.8, "longitude": 84.1 },
+ "annotations": { "latitude": 33.8, "longitude": -84.1 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
}
diff --git a/tools/test/topos/oe-nonlinear-4.json b/tools/test/topos/oe-nonlinear-4.json
index ac86a01..7082047 100644
--- a/tools/test/topos/oe-nonlinear-4.json
+++ b/tools/test/topos/oe-nonlinear-4.json
@@ -3,37 +3,37 @@
{
"uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM1",
- "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 },
- "ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" }, { "port": 22, "speed": 0, "type": "FIBER" }]
+ "annotations": { "latitude": 37.6, "longitude": -122.3, "optical.regens": 0 },
+ "ports": [ { "port": 10, "speed": 100000, "type": "FIBER" }, { "port": 20, "speed": 0, "type": "FIBER" }, { "port": 22, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM2",
- "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 },
- "ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" }, { "port": 22, "speed": 0, "type": "FIBER" }]
+ "annotations": { "latitude": 37.3, "longitude": -121.9, "optical.regens": 0 },
+ "ports": [ { "port": 11, "speed": 100000, "type": "FIBER" }, { "port": 21, "speed": 0, "type": "FIBER" }, { "port": 22, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM3",
- "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 },
- "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" }]
+ "annotations": { "latitude": 33.9, "longitude": -118.4, "optical.regens": 2 },
+ "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
- {
+ {
"uri": "of:0000ffffffffff04", "mac": "ffffffffffff04", "type":"ROADM",
"mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?", "name": "ROADM4",
- "annotations": { "latitude": 39.9, "longitude": 119.4, "optical.regens": 2 },
- "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" }]
+ "annotations": { "latitude": 39.9, "longitude": -119.4, "optical.regens": 2 },
+ "ports": [ { "port": 30, "speed": 0, "type": "FIBER" }, { "port": 31, "speed": 0, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0001", "mac": "ffffffffff0001", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER1",
- "annotations": { "latitude": 37.6, "longitude": 122.3 },
+ "annotations": { "latitude": 37.6, "longitude": -122.3 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
},
{
"uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH",
"mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?", "name": "ROUTER2",
- "annotations": { "latitude": 37.3, "longitude": 121.9 },
+ "annotations": { "latitude": 37.3, "longitude": -121.9 },
"ports": [ { "port": 1, "speed": 10000, "type": "COPPER" }, { "port": 2, "speed": 100000, "type": "FIBER" } ]
}
],
@@ -49,3 +49,4 @@
]
}
+
diff --git a/web/api/src/main/java/org/onlab/onos/rest/ConfigResource.java b/web/api/src/main/java/org/onlab/onos/rest/ConfigResource.java
index 34d5814..30fc51f 100644
--- a/web/api/src/main/java/org/onlab/onos/rest/ConfigResource.java
+++ b/web/api/src/main/java/org/onlab/onos/rest/ConfigResource.java
@@ -21,6 +21,8 @@
import org.onlab.onos.net.host.HostProviderRegistry;
import org.onlab.onos.net.link.LinkProviderRegistry;
import org.onlab.rest.BaseResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
@@ -31,6 +33,8 @@
import java.io.IOException;
import java.io.InputStream;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
/**
* Resource that acts as an ancillary provider for uploading pre-configured
* devices, ports and links.
@@ -38,17 +42,24 @@
@Path("config")
public class ConfigResource extends BaseResource {
+ private static Logger log = LoggerFactory.getLogger(ConfigResource.class);
+
@POST
@Path("topology")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response topology(InputStream input) throws IOException {
- ObjectMapper mapper = new ObjectMapper();
- JsonNode cfg = mapper.readTree(input);
- new ConfigProvider(cfg, get(DeviceProviderRegistry.class),
- get(LinkProviderRegistry.class),
- get(HostProviderRegistry.class)).parse();
- return Response.ok(mapper.createObjectNode().toString()).build();
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode cfg = mapper.readTree(input);
+ new ConfigProvider(cfg, get(DeviceProviderRegistry.class),
+ get(LinkProviderRegistry.class),
+ get(HostProviderRegistry.class)).parse();
+ return Response.ok(mapper.createObjectNode().toString()).build();
+ } catch (Exception e) {
+ log.error("Unable to parse topology configuration", e);
+ return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString()).build();
+ }
}
}
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java
index f747423..e7bc37e 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyMessages.java
@@ -40,7 +40,12 @@
import org.onlab.onos.net.device.DeviceService;
import org.onlab.onos.net.host.HostEvent;
import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.intent.ConnectivityIntent;
+import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentService;
+import org.onlab.onos.net.intent.IntentState;
+import org.onlab.onos.net.intent.LinkCollectionIntent;
+import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.link.LinkEvent;
import org.onlab.onos.net.link.LinkService;
import org.onlab.onos.net.provider.ProviderId;
@@ -50,6 +55,7 @@
import org.slf4j.LoggerFactory;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -350,7 +356,7 @@
new Prop("Longitude", annot.value("longitude"))));
}
- // Produces a path message to the client.
+ // Produces a path payload to the client.
protected ObjectNode pathMessage(Path path, String type) {
ObjectNode payload = mapper.createObjectNode();
ArrayNode links = mapper.createArrayNode();
@@ -362,6 +368,50 @@
return payload;
}
+
+ // Produces JSON message to trigger traffic visualization
+ protected ObjectNode trafficMessage(Set<Intent> intents, long sid) {
+ ObjectNode payload = mapper.createObjectNode();
+ ArrayNode paths = mapper.createArrayNode();
+ payload.set("paths", paths);
+
+ for (Intent intent : intents) {
+ List<Intent> installables = intentService.getInstallableIntents(intent.id());
+ IntentState state = intentService.getIntentState(intent.id());
+ String type = state == IntentState.FAILED ? "inactive" : "active";
+ for (Intent installable : installables) {
+ if (installable instanceof ConnectivityIntent) {
+ addPathTraffic(paths, type, (ConnectivityIntent) installable);
+ }
+ }
+ }
+
+ return envelope("showTraffic", sid, payload);
+ }
+
+ // Adds the link segments (path or tree) associated with the specified
+ // connectivity intent
+ protected void addPathTraffic(ArrayNode paths, String type,
+ ConnectivityIntent installable) {
+ ObjectNode pathNode = mapper.createObjectNode();
+ ArrayNode linksNode = mapper.createArrayNode();
+
+ Iterable<Link> links;
+ if (installable instanceof PathIntent) {
+ links = ((PathIntent) installable).path().links();
+ } else if (installable instanceof LinkCollectionIntent) {
+ links = ((LinkCollectionIntent) installable).links();
+ } else {
+ return;
+ }
+
+ for (Link link : links) {
+ linksNode.add(compactLinkString(link));
+ }
+ pathNode.put("type", type).set("links", linksNode);
+ paths.add(pathNode);
+ }
+
// Produces compact string representation of a link.
private static String compactLinkString(Link link) {
return String.format(COMPACT, link.src().elementId(), link.src().port(),
diff --git a/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java b/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java
index e4bfccd..46bc930 100644
--- a/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java
+++ b/web/gui/src/main/java/org/onlab/onos/gui/TopologyWebSocket.java
@@ -15,6 +15,8 @@
*/
package org.onlab.onos.gui;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.eclipse.jetty.websocket.WebSocket;
import org.onlab.onos.cluster.ClusterEvent;
@@ -24,6 +26,7 @@
import org.onlab.onos.core.CoreService;
import org.onlab.onos.mastership.MastershipEvent;
import org.onlab.onos.mastership.MastershipListener;
+import org.onlab.onos.net.ConnectPoint;
import org.onlab.onos.net.Device;
import org.onlab.onos.net.Host;
import org.onlab.onos.net.HostId;
@@ -38,16 +41,19 @@
import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.Intent;
import org.onlab.onos.net.intent.IntentEvent;
-import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.intent.IntentListener;
+import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
import org.onlab.onos.net.intent.PathIntent;
+import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.link.LinkEvent;
import org.onlab.onos.net.link.LinkListener;
import org.onlab.osgi.ServiceDirectory;
import java.io.IOException;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_ADDED;
@@ -85,9 +91,10 @@
private final IntentListener intentListener = new InternalIntentListener();
// Intents that are being monitored for the GUI
- private static Map<IntentId, Long> intentsToMonitor = new ConcurrentHashMap<>();
+ private static Map<Intent, Long> intentsToMonitor = new ConcurrentHashMap<>();
private long lastActive = System.currentTimeMillis();
+ private boolean listenersRemoved = false;
/**
* Creates a new web-socket for serving data to GUI topology view.
@@ -103,8 +110,8 @@
* Issues a close on the connection.
*/
synchronized void close() {
+ removeListeners();
if (connection.isOpen()) {
- removeListeners();
connection.close();
}
}
@@ -140,9 +147,7 @@
@Override
public synchronized void onClose(int closeCode, String message) {
- if (connection.isOpen()) {
- removeListeners();
- }
+ removeListeners();
log.info("GUI client disconnected");
}
@@ -165,7 +170,7 @@
} else if (type.equals("requestPath")) {
createHostIntent(event);
} else if (type.equals("requestTraffic")) {
- sendTraffic(event);
+ requestTraffic(event);
} else if (type.equals("cancelTraffic")) {
cancelTraffic(event);
}
@@ -217,12 +222,12 @@
private void requestDetails(ObjectNode event) {
ObjectNode payload = payload(event);
String type = string(payload, "class", "unknown");
+ long sid = number(event, "sid");
+
if (type.equals("device")) {
- sendMessage(deviceDetails(deviceId(string(payload, "id")),
- number(event, "sid")));
+ sendMessage(deviceDetails(deviceId(string(payload, "id")), sid));
} else if (type.equals("host")) {
- sendMessage(hostDetails(hostId(string(payload, "id")),
- number(event, "sid")));
+ sendMessage(hostDetails(hostId(string(payload, "id")), sid));
}
}
@@ -237,27 +242,137 @@
HostToHostIntent hostIntent = new HostToHostIntent(appId, one, two,
DefaultTrafficSelector.builder().build(),
DefaultTrafficTreatment.builder().build());
- intentsToMonitor.put(hostIntent.id(), number(event, "sid"));
+ intentsToMonitor.put(hostIntent, number(event, "sid"));
intentService.submit(hostIntent);
}
// Sends traffic message.
- private void sendTraffic(ObjectNode event) {
+ private void requestTraffic(ObjectNode event) {
ObjectNode payload = payload(event);
- long id = number(event, "sid");
- IntentId intentId = IntentId.valueOf(payload.path("intentId").asLong());
+ long sid = number(event, "sid");
+ Set<Intent> intents = findPathIntents(payload);
- if (payload != null) {
- payload.put("traffic", true);
- sendMessage(envelope("showPath", id, payload));
- } else {
- sendMessage(warning(id, "No path found"));
+ // Add all those intents to the list of monitored intents & flows.
+ intentsToMonitor.clear();
+ for (Intent intent : intents) {
+ intentsToMonitor.put(intent, sid);
}
+
+ // Send an initial message to highlight all links of all monitored intents.
+ sendMessage(trafficMessage(intents, sid));
}
// Cancels sending traffic messages.
private void cancelTraffic(ObjectNode event) {
- // TODO: implement this
+ ObjectNode payload = payload(event);
+ long sid = number(event, "sid");
+ Set<Intent> intents = findPathIntents(payload);
+
+ // Remove all those intents from the list of monitored intents & flows.
+ intentsToMonitor.clear(); // TODO: remove when ready
+ for (Intent intent : intents) {
+ intentsToMonitor.remove(intent.id());
+ }
+ sendMessage(trafficMessage(intents, sid));
+ }
+
+ // Finds all path (host-to-host or point-to-point) intents that pertains
+ // to the hosts indicated in the given event payload.
+ private Set<Intent> findPathIntents(ObjectNode payload) {
+ // Get the list of selected hosts.
+ Set<Host> hosts = getHosts((ArrayNode) payload.path("ids"));
+
+ // Derive from this the set of edge connect points.
+ Set<ConnectPoint> edgePoints = getEdgePoints(hosts);
+
+ // Iterate over all intents and produce a set that contains only those
+ // intents that target all selected hosts or derived edge connect points.
+ return getIntents(hosts, edgePoints);
+ }
+
+ // Produces a set of intents that target all selected hosts or connect points.
+ private Set<Intent> getIntents(Set<Host> hosts, Set<ConnectPoint> edgePoints) {
+ Set<Intent> intents = new HashSet<>();
+ for (Intent intent : intentService.getIntents()) {
+ boolean isRelevant = false;
+ if (intent instanceof HostToHostIntent) {
+ isRelevant = isIntentRelevant((HostToHostIntent) intent, hosts);
+ } else if (intent instanceof PointToPointIntent) {
+ isRelevant = isIntentRelevant((PointToPointIntent) intent, edgePoints);
+ } else if (intent instanceof MultiPointToSinglePointIntent) {
+ isRelevant = isIntentRelevant((MultiPointToSinglePointIntent) intent, edgePoints);
+ }
+ // TODO: add other intents, e.g. SinglePointToMultiPointIntent
+
+ if (isRelevant) {
+ intents.add(intent);
+ }
+ }
+ return intents;
+ }
+
+ // Indicates whether the specified intent involves all of the given hosts.
+ private boolean isIntentRelevant(HostToHostIntent intent, Set<Host> hosts) {
+ for (Host host : hosts) {
+ HostId id = host.id();
+ // Bail if intent does not involve this host.
+ if (!id.equals(intent.one()) && !id.equals(intent.two())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Indicates whether the specified intent involves all of the given edge points.
+ private boolean isIntentRelevant(PointToPointIntent intent,
+ Set<ConnectPoint> edgePoints) {
+ for (ConnectPoint point : edgePoints) {
+ // Bail if intent does not involve this edge point.
+ if (!point.equals(intent.egressPoint()) &&
+ !point.equals(intent.ingressPoint())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Indicates whether the specified intent involves all of the given edge points.
+ private boolean isIntentRelevant(MultiPointToSinglePointIntent intent,
+ Set<ConnectPoint> edgePoints) {
+ for (ConnectPoint point : edgePoints) {
+ // Bail if intent does not involve this edge point.
+ if (!point.equals(intent.egressPoint()) &&
+ !intent.ingressPoints().contains(point)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ // Produces a set of all host ids listed in the specified JSON array.
+ private Set<Host> getHosts(ArrayNode array) {
+ Set<Host> hosts = new HashSet<>();
+ for (JsonNode node : array) {
+ try {
+ Host host = hostService.getHost(hostId(node.asText()));
+ if (host != null) {
+ hosts.add(host);
+ }
+ } catch (IllegalArgumentException e) {
+ log.debug("Skipping ID {}", node.asText());
+ }
+ }
+ return hosts;
+ }
+
+ // Produces a set of edge points from the specified set of hosts.
+ private Set<ConnectPoint> getEdgePoints(Set<Host> hosts) {
+ Set<ConnectPoint> edgePoints = new HashSet<>();
+ for (Host host : hosts) {
+ edgePoints.add(host.location());
+ }
+ return edgePoints;
}
@@ -272,13 +387,16 @@
}
// Removes all internal listeners.
- private void removeListeners() {
- clusterService.removeListener(clusterListener);
- deviceService.removeListener(deviceListener);
- linkService.removeListener(linkListener);
- hostService.removeListener(hostListener);
- mastershipService.removeListener(mastershipListener);
- intentService.removeListener(intentListener);
+ private synchronized void removeListeners() {
+ if (!listenersRemoved) {
+ listenersRemoved = true;
+ clusterService.removeListener(clusterListener);
+ deviceService.removeListener(deviceListener);
+ linkService.removeListener(linkListener);
+ hostService.removeListener(hostListener);
+ mastershipService.removeListener(mastershipListener);
+ intentService.removeListener(intentListener);
+ }
}
// Cluster event listener.
@@ -327,7 +445,7 @@
@Override
public void event(IntentEvent event) {
Intent intent = event.subject();
- Long sid = intentsToMonitor.get(intent.id());
+ Long sid = intentsToMonitor.get(intent);
if (sid != null) {
List<Intent> installable = intentService.getInstallableIntents(intent.id());
if (installable != null && !installable.isEmpty()) {
diff --git a/web/gui/src/main/webapp/topo2.js b/web/gui/src/main/webapp/topo2.js
index 8934ec3..f93595f 100644
--- a/web/gui/src/main/webapp/topo2.js
+++ b/web/gui/src/main/webapp/topo2.js
@@ -130,8 +130,8 @@
U: unpin,
W: requestTraffic, // bag of selections
- Z: requestPath, // host-to-host intent (and monitor)
- X: cancelMonitor
+ X: cancelTraffic,
+ Z: requestPath // host-to-host intent (and monitor)
};
// state variables
@@ -496,7 +496,23 @@
}
function showTraffic(data) {
- network.view.alert("showTraffic() -- TODO")
+ fnTrace('showTraffic', data.payload.id);
+ data.payload.paths.forEach(function () {
+ var links = data.payload.links,
+ s = [ data.event + "\n" + links.length ];
+ links.forEach(function (d, i) {
+ s.push(d);
+ });
+ network.view.alert(s.join('\n'));
+
+ links.forEach(function (d, i) {
+ var link = network.lookup[d];
+ if (link) {
+ link.el.classed('showPath', true);
+ }
+ });
+ });
+ //network.view.alert("showTraffic() -- TODO")
}
// ...............................
@@ -566,9 +582,9 @@
}
}
- function cancelMonitor() {
+ function cancelTraffic() {
// FIXME: from where do we get the intent id(s) to send to the server?
- sendMessage('cancelMonitor', {
+ sendMessage('cancelTraffic', {
ids: ["need_the_intent_id"]
});
}