blob: db8cce026846b0af51d9f11e9518651329d8752c [file] [log] [blame]
tom8bb16062014-09-12 14:47:46 -07001package org.onlab.onos.tvue;
2
3import com.fasterxml.jackson.databind.ObjectMapper;
4import com.fasterxml.jackson.databind.node.ArrayNode;
5import com.fasterxml.jackson.databind.node.ObjectNode;
6import org.onlab.onos.net.ConnectPoint;
7import org.onlab.onos.net.ElementId;
tom025e09f2014-09-15 15:29:24 -07008import org.onlab.onos.net.Host;
tom8bb16062014-09-12 14:47:46 -07009import org.onlab.onos.net.Link;
toma33dd342014-09-12 19:07:40 -070010import org.onlab.onos.net.Path;
tom8bb16062014-09-12 14:47:46 -070011import org.onlab.onos.net.device.DeviceService;
12import org.onlab.onos.net.host.HostService;
13import org.onlab.onos.net.link.LinkService;
tom210f3f32014-09-16 17:33:40 -070014import org.onlab.onos.net.topology.PathService;
tom8bb16062014-09-12 14:47:46 -070015import org.onlab.onos.net.topology.Topology;
16import org.onlab.onos.net.topology.TopologyGraph;
17import org.onlab.onos.net.topology.TopologyService;
18import org.onlab.onos.net.topology.TopologyVertex;
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070019import org.onlab.packet.IpAddress;
tom8bb16062014-09-12 14:47:46 -070020import org.onlab.rest.BaseResource;
21
22import javax.ws.rs.GET;
tom6a9986b2014-09-12 18:44:52 -070023import javax.ws.rs.PathParam;
tom8bb16062014-09-12 14:47:46 -070024import javax.ws.rs.Produces;
25import javax.ws.rs.core.Response;
26import java.util.HashMap;
27import java.util.HashSet;
28import java.util.Map;
29import java.util.Set;
30
tom6a9986b2014-09-12 18:44:52 -070031import static org.onlab.onos.net.DeviceId.deviceId;
tomcbefa232014-09-16 14:17:20 -070032import static org.onlab.onos.net.HostId.hostId;
tom025e09f2014-09-15 15:29:24 -070033import static org.onlab.onos.net.PortNumber.portNumber;
tom6a9986b2014-09-12 18:44:52 -070034
tom8bb16062014-09-12 14:47:46 -070035/**
36 * Topology viewer resource.
37 */
tom6a9986b2014-09-12 18:44:52 -070038@javax.ws.rs.Path("topology")
tom8bb16062014-09-12 14:47:46 -070039public class TopologyResource extends BaseResource {
40
tom6a9986b2014-09-12 18:44:52 -070041 @javax.ws.rs.Path("/graph")
tom8bb16062014-09-12 14:47:46 -070042 @GET
43 @Produces("application/json")
44 public Response graph() {
45 ObjectMapper mapper = new ObjectMapper();
46
47 // Fetch the services we'll be using.
48 DeviceService deviceService = get(DeviceService.class);
49 HostService hostService = get(HostService.class);
50 TopologyService topologyService = get(TopologyService.class);
51
52 // Fetch the current topology and its graph that we'll use to render.
53 Topology topo = topologyService.currentTopology();
54 TopologyGraph graph = topologyService.getGraph(topo);
55
56 // Build all interior vertexes, i.e. no end-station hosts yet
57 ArrayNode vertexesNode = mapper.createArrayNode();
58 for (TopologyVertex vertex : graph.getVertexes()) {
59 vertexesNode.add(json(mapper, vertex.deviceId(), 2,
tom4d0c6632014-09-15 23:27:01 -070060 vertex.deviceId().uri().getSchemeSpecificPart(),
tom8bb16062014-09-12 14:47:46 -070061 deviceService.isAvailable(vertex.deviceId())));
62 }
63
64 // Now scan all links and count number of them between the same devices
65 // using a normalized link key.
66 Map<String, AggLink> linkRecords = aggregateLinks();
67
68 // Now build all interior edges using the aggregated links.
69 ArrayNode edgesNode = mapper.createArrayNode();
70 for (AggLink lr : linkRecords.values()) {
71 edgesNode.add(json(mapper, lr.links.size(), lr.link.src(), lr.link.dst()));
72 }
73
74 // Merge the exterior and interior vertexes and inject host links as
75 // the exterior edges.
tom025e09f2014-09-15 15:29:24 -070076 for (Host host : hostService.getHosts()) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070077 Set<IpAddress> ipAddresses = host.ipAddresses();
78 IpAddress ipAddress = ipAddresses.isEmpty() ? null : ipAddresses.iterator().next();
tom4d0c6632014-09-15 23:27:01 -070079 String label = ipAddress != null ? ipAddress.toString() : host.mac().toString();
80 vertexesNode.add(json(mapper, host.id(), 3, label, true));
tom025e09f2014-09-15 15:29:24 -070081 edgesNode.add(json(mapper, 1, host.location(), new ConnectPoint(host.id(), portNumber(-1))));
82 }
tom8bb16062014-09-12 14:47:46 -070083
84 // Now put the vertexes and edges into a root node and ship them off
85 ObjectNode rootNode = mapper.createObjectNode();
tom4d0c6632014-09-15 23:27:01 -070086 rootNode.set("vertexes", vertexesNode);
87 rootNode.set("edges", edgesNode);
tom8bb16062014-09-12 14:47:46 -070088 return Response.ok(rootNode.toString()).build();
89 }
90
tom6a9986b2014-09-12 18:44:52 -070091
tom6a9986b2014-09-12 18:44:52 -070092 /**
93 * Returns a JSON array of all paths between the specified hosts.
94 *
95 * @param src source host id
96 * @param dst target host id
97 * @return JSON array of paths
98 */
99 @javax.ws.rs.Path("/paths/{src}/{dst}")
100 @GET
101 @Produces("application/json")
102 public Response paths(@PathParam("src") String src, @PathParam("dst") String dst) {
103 ObjectMapper mapper = new ObjectMapper();
tomcbefa232014-09-16 14:17:20 -0700104 PathService pathService = get(PathService.class);
105 Set<Path> paths = pathService.getPaths(elementId(src), elementId(dst));
tom6a9986b2014-09-12 18:44:52 -0700106
107 ArrayNode pathsNode = mapper.createArrayNode();
tomcbefa232014-09-16 14:17:20 -0700108 for (Path path : paths) {
toma33dd342014-09-12 19:07:40 -0700109 pathsNode.add(json(mapper, path));
110 }
tom6a9986b2014-09-12 18:44:52 -0700111
112 // Now put the vertexes and edges into a root node and ship them off
113 ObjectNode rootNode = mapper.createObjectNode();
toma33dd342014-09-12 19:07:40 -0700114 rootNode.set("paths", pathsNode);
tom6a9986b2014-09-12 18:44:52 -0700115 return Response.ok(rootNode.toString()).build();
116 }
117
tomcbefa232014-09-16 14:17:20 -0700118 // Creates either device ID or host ID as appropriate.
119 private ElementId elementId(String id) {
120 return id.startsWith("nic:") ? hostId(id) : deviceId(id);
121 }
122
tom8bb16062014-09-12 14:47:46 -0700123 // Scan all links and counts number of them between the same devices
124 // using a normalized link key.
125 private Map<String, AggLink> aggregateLinks() {
126 Map<String, AggLink> aggLinks = new HashMap<>();
127 LinkService linkService = get(LinkService.class);
128 for (Link link : linkService.getLinks()) {
129 String key = key(link);
130 AggLink lr = aggLinks.get(key);
131 if (lr == null) {
132 lr = new AggLink(key);
133 aggLinks.put(key, lr);
134 }
135 lr.addLink(link);
136 }
137 return aggLinks;
138 }
139
140 // Produces JSON for a graph vertex.
141 private ObjectNode json(ObjectMapper mapper, ElementId id, int group,
tom4d0c6632014-09-15 23:27:01 -0700142 String label, boolean isOnline) {
tom8bb16062014-09-12 14:47:46 -0700143 return mapper.createObjectNode()
toma33dd342014-09-12 19:07:40 -0700144 .put("name", id.uri().toString())
tom4d0c6632014-09-15 23:27:01 -0700145 .put("label", label)
tom8bb16062014-09-12 14:47:46 -0700146 .put("group", group)
147 .put("online", isOnline);
148 }
149
150 // Produces JSON for a graph edge.
151 private ObjectNode json(ObjectMapper mapper, int count,
152 ConnectPoint src, ConnectPoint dst) {
153 return json(mapper, count, id(src), id(dst));
154 }
155
156 // Produces JSON for a graph edge.
157 private ObjectNode json(ObjectMapper mapper, int count, String src, String dst) {
158 return mapper.createObjectNode()
159 .put("source", src).put("target", dst).put("value", count);
160 }
161
toma33dd342014-09-12 19:07:40 -0700162 // Produces JSON representation of a network path.
163 private ArrayNode json(ObjectMapper mapper, Path path) {
164 ArrayNode pathNode = mapper.createArrayNode();
165 for (Link link : path.links()) {
166 ObjectNode linkNode = mapper.createObjectNode()
167 .put("src", id(link.src()))
168 .put("dst", id(link.dst()));
169 pathNode.add(linkNode);
170 }
171 return pathNode;
172 }
173
174
tom8bb16062014-09-12 14:47:46 -0700175 // Aggregate link of all links between the same devices regardless of
176 // their direction.
177 private class AggLink {
178 Link link; // representative links
179
180 final String key;
181 final Set<Link> links = new HashSet<>();
182
183 AggLink(String key) {
184 this.key = key;
185 }
186
187 void addLink(Link link) {
188 links.add(link);
189 if (this.link == null) {
190 this.link = link;
191 }
192 }
193 }
194
195 // Returns a canonical key for the specified link.
196 static String key(Link link) {
197 String s = id(link.src());
198 String d = id(link.dst());
199 return s.compareTo(d) > 0 ? d + s : s + d;
200 }
201
202 // Returns a formatted string for the element associated with the given
203 // connection point.
204 private static String id(ConnectPoint cp) {
toma33dd342014-09-12 19:07:40 -0700205 return cp.elementId().uri().toString();
tom8bb16062014-09-12 14:47:46 -0700206 }
207
208}