Thomas Vachuska
Committed by Gerrit Code Review

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
......@@ -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.Constraint;
import org.onlab.onos.net.intent.HostToHostIntent;
import org.onlab.onos.net.intent.IntentService;
import java.util.List;
/**
* Installs host-to-host connectivity intent.
*/
......
......@@ -20,11 +20,13 @@ import java.util.List;
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 @@ public abstract class ConnectivityIntentCommand extends AbstractShellCommand {
if (lambda) {
constraints.add(new LambdaConstraint(null));
}
constraints.add(new LinkTypeConstraint(lambda, Link.Type.OPTICAL));
return constraints;
}
......
......@@ -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 final class HostToHostIntent extends ConnectivityIntent {
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)));
}
/**
......
......@@ -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" } ]
}
],
......
......@@ -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" } ]
}
......
......@@ -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 @@
]
}
......
......@@ -21,6 +21,8 @@ import org.onlab.onos.net.device.DeviceProviderRegistry;
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 javax.ws.rs.core.Response;
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 @@ import java.io.InputStream;
@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();
}
}
}
......
......@@ -40,7 +40,12 @@ import org.onlab.onos.net.device.DeviceEvent;
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.Logger;
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 @@ public abstract class TopologyMessages {
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 @@ public abstract class TopologyMessages {
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(),
......
......@@ -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.ApplicationId;
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.host.HostListener;
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 @@ public class TopologyWebSocket
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 @@ public class TopologyWebSocket
* Issues a close on the connection.
*/
synchronized void close() {
removeListeners();
if (connection.isOpen()) {
removeListeners();
connection.close();
}
}
......@@ -140,9 +147,7 @@ public class TopologyWebSocket
@Override
public synchronized void onClose(int closeCode, String message) {
if (connection.isOpen()) {
removeListeners();
}
removeListeners();
log.info("GUI client disconnected");
}
......@@ -165,7 +170,7 @@ public class TopologyWebSocket
} 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 @@ public class TopologyWebSocket
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 @@ public class TopologyWebSocket
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 @@ public class TopologyWebSocket
}
// 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 @@ public class TopologyWebSocket
@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()) {
......
......@@ -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"]
});
}
......