blob: 872a0998b3b859eac35344c79b62e7b6240c9438 [file] [log] [blame]
Thomas Vachuska329af532015-03-10 02:08:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska329af532015-03-10 02:08:33 -07003 *
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 */
16package org.onosproject.ui.impl;
17
18import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuska329af532015-03-10 02:08:33 -070019import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.onlab.osgi.ServiceDirectory;
22import org.onlab.packet.IpAddress;
Simon Hunt95d56fd2015-11-12 11:06:44 -080023import org.onlab.util.DefaultHashMap;
Thomas Vachuska329af532015-03-10 02:08:33 -070024import org.onosproject.cluster.ClusterEvent;
25import org.onosproject.cluster.ClusterService;
26import org.onosproject.cluster.ControllerNode;
27import org.onosproject.cluster.NodeId;
28import org.onosproject.core.CoreService;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -070029import org.onosproject.incubator.net.PortStatisticsService;
cheng fan35dc0f22015-06-10 06:02:47 +080030import org.onosproject.incubator.net.tunnel.OpticalTunnelEndPoint;
31import org.onosproject.incubator.net.tunnel.Tunnel;
32import org.onosproject.incubator.net.tunnel.TunnelService;
Thomas Vachuska329af532015-03-10 02:08:33 -070033import org.onosproject.mastership.MastershipService;
chengfanc553c952016-07-22 15:48:23 +080034import org.onosproject.net.ElementId;
Thomas Vachuska329af532015-03-10 02:08:33 -070035import org.onosproject.net.Annotated;
36import org.onosproject.net.AnnotationKeys;
37import org.onosproject.net.Annotations;
38import org.onosproject.net.ConnectPoint;
39import org.onosproject.net.DefaultEdgeLink;
40import org.onosproject.net.Device;
41import org.onosproject.net.DeviceId;
42import org.onosproject.net.EdgeLink;
43import org.onosproject.net.Host;
44import org.onosproject.net.HostId;
45import org.onosproject.net.HostLocation;
46import org.onosproject.net.Link;
Thomas Vachuska329af532015-03-10 02:08:33 -070047import org.onosproject.net.PortNumber;
48import org.onosproject.net.device.DeviceEvent;
49import org.onosproject.net.device.DeviceService;
50import org.onosproject.net.flow.FlowEntry;
51import org.onosproject.net.flow.FlowRuleService;
52import org.onosproject.net.flow.TrafficTreatment;
53import org.onosproject.net.flow.instructions.Instruction;
54import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
55import org.onosproject.net.host.HostEvent;
56import org.onosproject.net.host.HostService;
Thomas Vachuska329af532015-03-10 02:08:33 -070057import org.onosproject.net.intent.IntentService;
Thomas Vachuska329af532015-03-10 02:08:33 -070058import org.onosproject.net.link.LinkEvent;
59import org.onosproject.net.link.LinkService;
60import org.onosproject.net.provider.ProviderId;
Thomas Vachuska329af532015-03-10 02:08:33 -070061import org.onosproject.net.statistic.StatisticService;
62import org.onosproject.net.topology.Topology;
63import org.onosproject.net.topology.TopologyService;
Simon Huntd2747a02015-04-30 22:41:16 -070064import org.onosproject.ui.JsonUtils;
Thomas Vachuska329af532015-03-10 02:08:33 -070065import org.onosproject.ui.UiConnection;
Simon Hunta0ddb022015-05-01 09:53:01 -070066import org.onosproject.ui.UiMessageHandler;
Simon Hunted804d52016-03-30 09:51:40 -070067import org.onosproject.ui.impl.topo.util.ServicesBundle;
Simon Hunt0af1ec32015-07-24 12:17:55 -070068import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
71
Thomas Vachuska329af532015-03-10 02:08:33 -070072import java.util.ArrayList;
73import java.util.Collection;
74import java.util.Collections;
75import java.util.HashMap;
76import java.util.HashSet;
77import java.util.Iterator;
78import java.util.List;
79import java.util.Map;
80import java.util.Set;
chengfanc553c952016-07-22 15:48:23 +080081import java.util.Optional;
Thomas Vachuska329af532015-03-10 02:08:33 -070082import java.util.concurrent.ConcurrentHashMap;
83
84import static com.google.common.base.Preconditions.checkNotNull;
85import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuska204cb6c2015-06-04 00:03:06 -070086import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Thomas Vachuska329af532015-03-10 02:08:33 -070087import static org.onosproject.net.PortNumber.portNumber;
Simon Hunt3a0598f2015-08-04 19:59:04 -070088import static org.onosproject.ui.topo.TopoConstants.CoreButtons;
89import static org.onosproject.ui.topo.TopoConstants.Properties;
Simon Huntd3ceffa2015-08-25 12:44:35 -070090import static org.onosproject.ui.topo.TopoUtils.compactLinkString;
Thomas Vachuska329af532015-03-10 02:08:33 -070091
92/**
93 * Facility for creating messages bound for the topology viewer.
94 */
Simon Hunta0ddb022015-05-01 09:53:01 -070095public abstract class TopologyViewMessageHandlerBase extends UiMessageHandler {
Thomas Vachuska329af532015-03-10 02:08:33 -070096
Simon Hunt95d56fd2015-11-12 11:06:44 -080097 // default to an "add" event...
98 private static final DefaultHashMap<ClusterEvent.Type, String> CLUSTER_EVENT =
99 new DefaultHashMap<>("addInstance");
100
101 // default to an "update" event...
102 private static final DefaultHashMap<DeviceEvent.Type, String> DEVICE_EVENT =
103 new DefaultHashMap<>("updateDevice");
104 private static final DefaultHashMap<LinkEvent.Type, String> LINK_EVENT =
105 new DefaultHashMap<>("updateLink");
106 private static final DefaultHashMap<HostEvent.Type, String> HOST_EVENT =
107 new DefaultHashMap<>("updateHost");
108
109 // but call out specific events that we care to differentiate...
110 static {
111 CLUSTER_EVENT.put(ClusterEvent.Type.INSTANCE_REMOVED, "removeInstance");
112
113 DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_ADDED, "addDevice");
114 DEVICE_EVENT.put(DeviceEvent.Type.DEVICE_REMOVED, "removeDevice");
115
116 LINK_EVENT.put(LinkEvent.Type.LINK_ADDED, "addLink");
117 LINK_EVENT.put(LinkEvent.Type.LINK_REMOVED, "removeLink");
118
119 HOST_EVENT.put(HostEvent.Type.HOST_ADDED, "addHost");
120 HOST_EVENT.put(HostEvent.Type.HOST_REMOVED, "removeHost");
121 HOST_EVENT.put(HostEvent.Type.HOST_MOVED, "moveHost");
122 }
123
Simon Huntd2747a02015-04-30 22:41:16 -0700124 protected static final Logger log =
125 LoggerFactory.getLogger(TopologyViewMessageHandlerBase.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700126
Simon Huntd2747a02015-04-30 22:41:16 -0700127 private static final ProviderId PID =
128 new ProviderId("core", "org.onosproject.core", true);
Thomas Vachuska329af532015-03-10 02:08:33 -0700129
Simon Hunta17fa672015-08-19 18:42:22 -0700130 protected static final String SHOW_HIGHLIGHTS = "showHighlights";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700131
Thomas Vachuska329af532015-03-10 02:08:33 -0700132 protected ServiceDirectory directory;
133 protected ClusterService clusterService;
134 protected DeviceService deviceService;
135 protected LinkService linkService;
136 protected HostService hostService;
137 protected MastershipService mastershipService;
138 protected IntentService intentService;
139 protected FlowRuleService flowService;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700140 protected StatisticService flowStatsService;
141 protected PortStatisticsService portStatsService;
Thomas Vachuska329af532015-03-10 02:08:33 -0700142 protected TopologyService topologyService;
cheng fan35dc0f22015-06-10 06:02:47 +0800143 protected TunnelService tunnelService;
Thomas Vachuska329af532015-03-10 02:08:33 -0700144
Simon Hunta17fa672015-08-19 18:42:22 -0700145 protected ServicesBundle servicesBundle;
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700146
Thomas Vachuska329af532015-03-10 02:08:33 -0700147 private String version;
148
149 // TODO: extract into an external & durable state; good enough for now and demo
150 private static Map<String, ObjectNode> metaUi = new ConcurrentHashMap<>();
151
152 /**
Thomas Vachuska329af532015-03-10 02:08:33 -0700153 * Returns read-only view of the meta-ui information.
154 *
155 * @return map of id to meta-ui mementos
156 */
157 static Map<String, ObjectNode> getMetaUi() {
158 return Collections.unmodifiableMap(metaUi);
159 }
160
161 @Override
162 public void init(UiConnection connection, ServiceDirectory directory) {
163 super.init(connection, directory);
164 this.directory = checkNotNull(directory, "Directory cannot be null");
165 clusterService = directory.get(ClusterService.class);
166 deviceService = directory.get(DeviceService.class);
167 linkService = directory.get(LinkService.class);
168 hostService = directory.get(HostService.class);
169 mastershipService = directory.get(MastershipService.class);
170 intentService = directory.get(IntentService.class);
171 flowService = directory.get(FlowRuleService.class);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700172 flowStatsService = directory.get(StatisticService.class);
173 portStatsService = directory.get(PortStatisticsService.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700174 topologyService = directory.get(TopologyService.class);
cheng fan35dc0f22015-06-10 06:02:47 +0800175 tunnelService = directory.get(TunnelService.class);
Thomas Vachuska329af532015-03-10 02:08:33 -0700176
Simon Hunta17fa672015-08-19 18:42:22 -0700177 servicesBundle = new ServicesBundle(intentService, deviceService,
178 hostService, linkService,
179 flowService,
180 flowStatsService, portStatsService);
181
Thomas Vachuska329af532015-03-10 02:08:33 -0700182 String ver = directory.get(CoreService.class).version().toString();
183 version = ver.replace(".SNAPSHOT", "*").replaceFirst("~.*$", "");
184 }
185
Thomas Vachuska329af532015-03-10 02:08:33 -0700186 // Returns the specified set of IP addresses as a string.
187 private String ip(Set<IpAddress> ipAddresses) {
188 Iterator<IpAddress> it = ipAddresses.iterator();
189 return it.hasNext() ? it.next().toString() : "unknown";
190 }
191
192 // Produces JSON structure from annotations.
193 private JsonNode props(Annotations annotations) {
Simon Huntda580882015-05-12 20:58:18 -0700194 ObjectNode props = objectNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700195 if (annotations != null) {
196 for (String key : annotations.keys()) {
197 props.put(key, annotations.value(key));
198 }
199 }
200 return props;
201 }
202
203 // Produces an informational log message event bound to the client.
204 protected ObjectNode info(long id, String message) {
205 return message("info", id, message);
206 }
207
208 // Produces a warning log message event bound to the client.
209 protected ObjectNode warning(long id, String message) {
210 return message("warning", id, message);
211 }
212
213 // Produces an error log message event bound to the client.
214 protected ObjectNode error(long id, String message) {
215 return message("error", id, message);
216 }
217
218 // Produces a log message event bound to the client.
219 private ObjectNode message(String severity, long id, String message) {
Simon Huntda580882015-05-12 20:58:18 -0700220 ObjectNode payload = objectNode()
Simon Huntd2747a02015-04-30 22:41:16 -0700221 .put("severity", severity)
222 .put("message", message);
Thomas Vachuska329af532015-03-10 02:08:33 -0700223
Simon Huntd2747a02015-04-30 22:41:16 -0700224 return JsonUtils.envelope("message", id, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700225 }
226
Thomas Vachuska329af532015-03-10 02:08:33 -0700227 // Produces a cluster instance message to the client.
Simon Hunt95d56fd2015-11-12 11:06:44 -0800228 protected ObjectNode instanceMessage(ClusterEvent event, String msgType) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700229 ControllerNode node = event.subject();
230 int switchCount = mastershipService.getDevicesOf(node.id()).size();
Simon Huntda580882015-05-12 20:58:18 -0700231 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700232 .put("id", node.id().toString())
233 .put("ip", node.ip().toString())
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800234 .put("online", clusterService.getState(node.id()).isActive())
Thomas Vachuskafba7f3d2016-03-23 15:46:25 -0700235 .put("ready", clusterService.getState(node.id()).isReady())
Thomas Vachuskab6acc7b2015-03-11 09:11:21 -0700236 .put("uiAttached", node.equals(clusterService.getLocalNode()))
Thomas Vachuska329af532015-03-10 02:08:33 -0700237 .put("switches", switchCount);
238
Simon Huntda580882015-05-12 20:58:18 -0700239 ArrayNode labels = arrayNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700240 labels.add(node.id().toString());
241 labels.add(node.ip().toString());
242
243 // Add labels, props and stuff the payload into envelope.
244 payload.set("labels", labels);
245 addMetaUi(node.id().toString(), payload);
246
Simon Hunt95d56fd2015-11-12 11:06:44 -0800247 String type = msgType != null ? msgType : CLUSTER_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700248 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700249 }
250
251 // Produces a device event message to the client.
252 protected ObjectNode deviceMessage(DeviceEvent event) {
253 Device device = event.subject();
Simon Huntda580882015-05-12 20:58:18 -0700254 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700255 .put("id", device.id().toString())
256 .put("type", device.type().toString().toLowerCase())
257 .put("online", deviceService.isAvailable(device.id()))
258 .put("master", master(device.id()));
259
260 // Generate labels: id, chassis id, no-label, optional-name
261 String name = device.annotations().value(AnnotationKeys.NAME);
Simon Huntda580882015-05-12 20:58:18 -0700262 ArrayNode labels = arrayNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700263 labels.add("");
264 labels.add(isNullOrEmpty(name) ? device.id().toString() : name);
265 labels.add(device.id().toString());
266
267 // Add labels, props and stuff the payload into envelope.
268 payload.set("labels", labels);
269 payload.set("props", props(device.annotations()));
270 addGeoLocation(device, payload);
271 addMetaUi(device.id().toString(), payload);
272
Simon Hunt95d56fd2015-11-12 11:06:44 -0800273 String type = DEVICE_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700274 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700275 }
276
277 // Produces a link event message to the client.
278 protected ObjectNode linkMessage(LinkEvent event) {
279 Link link = event.subject();
Simon Huntda580882015-05-12 20:58:18 -0700280 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700281 .put("id", compactLinkString(link))
282 .put("type", link.type().toString().toLowerCase())
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800283 .put("expected", link.isExpected())
Thomas Vachuska329af532015-03-10 02:08:33 -0700284 .put("online", link.state() == Link.State.ACTIVE)
285 .put("linkWidth", 1.2)
286 .put("src", link.src().deviceId().toString())
287 .put("srcPort", link.src().port().toString())
288 .put("dst", link.dst().deviceId().toString())
289 .put("dstPort", link.dst().port().toString());
Simon Hunt95d56fd2015-11-12 11:06:44 -0800290 String type = LINK_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700291 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700292 }
293
294 // Produces a host event message to the client.
295 protected ObjectNode hostMessage(HostEvent event) {
296 Host host = event.subject();
Charles Chan33f28a92015-11-13 13:12:38 -0800297 Host prevHost = event.prevSubject();
Thomas Vachuska329af532015-03-10 02:08:33 -0700298 String hostType = host.annotations().value(AnnotationKeys.TYPE);
Simon Hunt95d56fd2015-11-12 11:06:44 -0800299
Simon Huntda580882015-05-12 20:58:18 -0700300 ObjectNode payload = objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700301 .put("id", host.id().toString())
302 .put("type", isNullOrEmpty(hostType) ? "endstation" : hostType)
303 .put("ingress", compactLinkString(edgeLink(host, true)))
304 .put("egress", compactLinkString(edgeLink(host, false)));
Simon Huntda580882015-05-12 20:58:18 -0700305 payload.set("cp", hostConnect(host.location()));
Charles Chan33f28a92015-11-13 13:12:38 -0800306 if (prevHost != null && prevHost.location() != null) {
307 payload.set("prevCp", hostConnect(prevHost.location()));
Simon Hunt95d56fd2015-11-12 11:06:44 -0800308 }
Simon Huntda580882015-05-12 20:58:18 -0700309 payload.set("labels", labels(ip(host.ipAddresses()),
Thomas Vachuska329af532015-03-10 02:08:33 -0700310 host.mac().toString()));
311 payload.set("props", props(host.annotations()));
312 addGeoLocation(host, payload);
313 addMetaUi(host.id().toString(), payload);
314
Simon Hunt95d56fd2015-11-12 11:06:44 -0800315 String type = HOST_EVENT.get(event.type());
Simon Huntd2747a02015-04-30 22:41:16 -0700316 return JsonUtils.envelope(type, 0, payload);
Thomas Vachuska329af532015-03-10 02:08:33 -0700317 }
318
319 // Encodes the specified host location into a JSON object.
Simon Huntda580882015-05-12 20:58:18 -0700320 private ObjectNode hostConnect(HostLocation location) {
321 return objectNode()
Thomas Vachuska329af532015-03-10 02:08:33 -0700322 .put("device", location.deviceId().toString())
323 .put("port", location.port().toLong());
324 }
325
326 // Encodes the specified list of labels a JSON array.
Simon Huntda580882015-05-12 20:58:18 -0700327 private ArrayNode labels(String... labels) {
328 ArrayNode json = arrayNode();
Thomas Vachuska329af532015-03-10 02:08:33 -0700329 for (String label : labels) {
330 json.add(label);
331 }
332 return json;
333 }
334
335 // Returns the name of the master node for the specified device id.
336 private String master(DeviceId deviceId) {
337 NodeId master = mastershipService.getMasterFor(deviceId);
338 return master != null ? master.toString() : "";
339 }
340
341 // Generates an edge link from the specified host location.
342 private EdgeLink edgeLink(Host host, boolean ingress) {
343 return new DefaultEdgeLink(PID, new ConnectPoint(host.id(), portNumber(0)),
344 host.location(), ingress);
345 }
346
347 // Adds meta UI information for the specified object.
348 private void addMetaUi(String id, ObjectNode payload) {
349 ObjectNode meta = metaUi.get(id);
350 if (meta != null) {
351 payload.set("metaUi", meta);
352 }
353 }
354
355 // Adds a geo location JSON to the specified payload object.
356 private void addGeoLocation(Annotated annotated, ObjectNode payload) {
357 Annotations annotations = annotated.annotations();
358 if (annotations == null) {
359 return;
360 }
361
Thomas Vachuska329af532015-03-10 02:08:33 -0700362 String slng = annotations.value(AnnotationKeys.LONGITUDE);
Simon Huntfd7106c2016-02-09 15:05:26 -0800363 String slat = annotations.value(AnnotationKeys.LATITUDE);
364 boolean haveLng = slng != null && !slng.isEmpty();
365 boolean haveLat = slat != null && !slat.isEmpty();
Thomas Vachuska329af532015-03-10 02:08:33 -0700366 try {
Simon Huntfd7106c2016-02-09 15:05:26 -0800367 if (haveLng && haveLat) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700368 double lng = Double.parseDouble(slng);
Simon Huntfd7106c2016-02-09 15:05:26 -0800369 double lat = Double.parseDouble(slat);
Simon Huntda580882015-05-12 20:58:18 -0700370 ObjectNode loc = objectNode()
Simon Huntfd7106c2016-02-09 15:05:26 -0800371 .put("type", "lnglat")
372 .put("lng", lng)
373 .put("lat", lat);
Thomas Vachuska329af532015-03-10 02:08:33 -0700374 payload.set("location", loc);
Simon Huntfd7106c2016-02-09 15:05:26 -0800375 } else {
376 log.trace("missing Lng/Lat: lng={}, lat={}", slng, slat);
Thomas Vachuska329af532015-03-10 02:08:33 -0700377 }
378 } catch (NumberFormatException e) {
Simon Huntfd7106c2016-02-09 15:05:26 -0800379 log.warn("Invalid geo data: longitude={}, latitude={}", slng, slat);
Thomas Vachuska329af532015-03-10 02:08:33 -0700380 }
381 }
382
383 // Updates meta UI information for the specified object.
Simon Huntd2747a02015-04-30 22:41:16 -0700384 protected void updateMetaUi(ObjectNode payload) {
385 metaUi.put(JsonUtils.string(payload, "id"),
386 JsonUtils.node(payload, "memento"));
Thomas Vachuska329af532015-03-10 02:08:33 -0700387 }
388
Simon Hunta17fa672015-08-19 18:42:22 -0700389
Simon Huntb745ca62015-07-28 15:37:11 -0700390 // -----------------------------------------------------------------------
391 // Create models of the data to return, that overlays can adjust / augment
392
393 // Returns property panel model for summary response.
Simon Hunt0af1ec32015-07-24 12:17:55 -0700394 protected PropertyPanel summmaryMessage(long sid) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700395 Topology topology = topologyService.currentTopology();
Simon Hunt0af1ec32015-07-24 12:17:55 -0700396
Simon Hunt00a27ff2015-07-28 18:53:40 -0700397 return new PropertyPanel("ONOS Summary", "node")
Thomas Vachuskae50b6212015-12-02 08:00:09 -0800398 .addProp(Properties.VERSION, version)
399 .addSeparator()
chengfanc553c952016-07-22 15:48:23 +0800400 .addProp(Properties.DEVICES, deviceService.getDeviceCount())
Simon Huntfb940112015-07-29 18:36:35 -0700401 .addProp(Properties.LINKS, topology.linkCount())
402 .addProp(Properties.HOSTS, hostService.getHostCount())
403 .addProp(Properties.TOPOLOGY_SSCS, topology.clusterCount())
Simon Hunt00a27ff2015-07-28 18:53:40 -0700404 .addSeparator()
Simon Huntfb940112015-07-29 18:36:35 -0700405 .addProp(Properties.INTENTS, intentService.getIntentCount())
406 .addProp(Properties.TUNNELS, tunnelService.tunnelCount())
Thomas Vachuskae50b6212015-12-02 08:00:09 -0800407 .addProp(Properties.FLOWS, flowService.getFlowRuleCount());
Thomas Vachuska329af532015-03-10 02:08:33 -0700408 }
409
Simon Huntb745ca62015-07-28 15:37:11 -0700410 // Returns property panel model for device details response.
411 protected PropertyPanel deviceDetails(DeviceId deviceId, long sid) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700412 Device device = deviceService.getDevice(deviceId);
413 Annotations annot = device.annotations();
414 String name = annot.value(AnnotationKeys.NAME);
415 int portCount = deviceService.getPorts(deviceId).size();
416 int flowCount = getFlowCount(deviceId);
cheng fan35dc0f22015-06-10 06:02:47 +0800417 int tunnelCount = getTunnelCount(deviceId);
Simon Huntb745ca62015-07-28 15:37:11 -0700418
419 String title = isNullOrEmpty(name) ? deviceId.toString() : name;
420 String typeId = device.type().toString().toLowerCase();
421
422 PropertyPanel pp = new PropertyPanel(title, typeId)
Simon Huntfb940112015-07-29 18:36:35 -0700423 .id(deviceId.toString())
Simon Hunt3a0598f2015-08-04 19:59:04 -0700424
Simon Huntfb940112015-07-29 18:36:35 -0700425 .addProp(Properties.URI, deviceId.toString())
426 .addProp(Properties.VENDOR, device.manufacturer())
427 .addProp(Properties.HW_VERSION, device.hwVersion())
428 .addProp(Properties.SW_VERSION, device.swVersion())
429 .addProp(Properties.SERIAL_NUMBER, device.serialNumber())
430 .addProp(Properties.PROTOCOL, annot.value(AnnotationKeys.PROTOCOL))
431 .addSeparator()
Simon Hunt3a0598f2015-08-04 19:59:04 -0700432
Simon Huntfb940112015-07-29 18:36:35 -0700433 .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
434 .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE))
435 .addSeparator()
Simon Hunt3a0598f2015-08-04 19:59:04 -0700436
Simon Huntfb940112015-07-29 18:36:35 -0700437 .addProp(Properties.PORTS, portCount)
438 .addProp(Properties.FLOWS, flowCount)
Simon Hunt3a0598f2015-08-04 19:59:04 -0700439 .addProp(Properties.TUNNELS, tunnelCount)
Simon Hunt00a27ff2015-07-28 18:53:40 -0700440
Simon Hunt3a0598f2015-08-04 19:59:04 -0700441 .addButton(CoreButtons.SHOW_DEVICE_VIEW)
442 .addButton(CoreButtons.SHOW_FLOW_VIEW)
443 .addButton(CoreButtons.SHOW_PORT_VIEW)
Jian Li79f67322016-01-06 18:22:37 -0800444 .addButton(CoreButtons.SHOW_GROUP_VIEW)
445 .addButton(CoreButtons.SHOW_METER_VIEW);
Simon Huntb745ca62015-07-28 15:37:11 -0700446
447 return pp;
Thomas Vachuska329af532015-03-10 02:08:33 -0700448 }
449
450 protected int getFlowCount(DeviceId deviceId) {
451 int count = 0;
Simon Huntb745ca62015-07-28 15:37:11 -0700452 for (FlowEntry flowEntry : flowService.getFlowEntries(deviceId)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700453 count++;
Thomas Vachuska329af532015-03-10 02:08:33 -0700454 }
455 return count;
456 }
457
cheng fan35dc0f22015-06-10 06:02:47 +0800458 protected int getTunnelCount(DeviceId deviceId) {
459 int count = 0;
460 Collection<Tunnel> tunnels = tunnelService.queryAllTunnels();
461 for (Tunnel tunnel : tunnels) {
chengfanc553c952016-07-22 15:48:23 +0800462 //Only OpticalTunnelEndPoint has a device
463 if (!(tunnel.src() instanceof OpticalTunnelEndPoint) ||
464 !(tunnel.dst() instanceof OpticalTunnelEndPoint)) {
465 continue;
466 }
467
468 Optional<ElementId> srcElementId = ((OpticalTunnelEndPoint) tunnel.src()).elementId();
469 Optional<ElementId> dstElementId = ((OpticalTunnelEndPoint) tunnel.dst()).elementId();
470 if (!srcElementId.isPresent() || !dstElementId.isPresent()) {
471 continue;
472 }
473 DeviceId srcDeviceId = (DeviceId) srcElementId.get();
474 DeviceId dstDeviceId = (DeviceId) dstElementId.get();
475 if (srcDeviceId.equals(deviceId) || dstDeviceId.equals(deviceId)) {
cheng fan35dc0f22015-06-10 06:02:47 +0800476 count++;
477 }
478 }
479 return count;
480 }
481
Simon Hunta17fa672015-08-19 18:42:22 -0700482 // Counts all flow entries that egress on the links of the given device.
483 private Map<Link, Integer> getLinkFlowCounts(DeviceId deviceId) {
484 // get the flows for the device
Thomas Vachuska329af532015-03-10 02:08:33 -0700485 List<FlowEntry> entries = new ArrayList<>();
Simon Huntb745ca62015-07-28 15:37:11 -0700486 for (FlowEntry flowEntry : flowService.getFlowEntries(deviceId)) {
487 entries.add(flowEntry);
Thomas Vachuska329af532015-03-10 02:08:33 -0700488 }
489
Simon Hunta17fa672015-08-19 18:42:22 -0700490 // get egress links from device, and include edge links
491 Set<Link> links = new HashSet<>(linkService.getDeviceEgressLinks(deviceId));
492 Set<Host> hosts = hostService.getConnectedHosts(deviceId);
Thomas Vachuska329af532015-03-10 02:08:33 -0700493 if (hosts != null) {
494 for (Host host : hosts) {
Simon Hunta17fa672015-08-19 18:42:22 -0700495 links.add(createEdgeLink(host, false));
Thomas Vachuska329af532015-03-10 02:08:33 -0700496 }
497 }
498
Simon Hunta17fa672015-08-19 18:42:22 -0700499 // compile flow counts per link
Thomas Vachuska329af532015-03-10 02:08:33 -0700500 Map<Link, Integer> counts = new HashMap<>();
501 for (Link link : links) {
502 counts.put(link, getEgressFlows(link, entries));
503 }
504 return counts;
505 }
506
507 // Counts all entries that egress on the link source port.
Simon Hunta17fa672015-08-19 18:42:22 -0700508 private int getEgressFlows(Link link, List<FlowEntry> entries) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700509 int count = 0;
510 PortNumber out = link.src().port();
511 for (FlowEntry entry : entries) {
512 TrafficTreatment treatment = entry.treatment();
Ray Milkey42507352015-03-20 15:16:10 -0700513 for (Instruction instruction : treatment.allInstructions()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700514 if (instruction.type() == Instruction.Type.OUTPUT &&
515 ((OutputInstruction) instruction).port().equals(out)) {
516 count++;
517 }
518 }
519 }
520 return count;
521 }
522
Thomas Vachuska329af532015-03-10 02:08:33 -0700523 // Returns host details response.
Simon Huntb745ca62015-07-28 15:37:11 -0700524 protected PropertyPanel hostDetails(HostId hostId, long sid) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700525 Host host = hostService.getHost(hostId);
526 Annotations annot = host.annotations();
527 String type = annot.value(AnnotationKeys.TYPE);
528 String name = annot.value(AnnotationKeys.NAME);
529 String vlan = host.vlan().toString();
Simon Huntb745ca62015-07-28 15:37:11 -0700530
531 String title = isNullOrEmpty(name) ? hostId.toString() : name;
532 String typeId = isNullOrEmpty(type) ? "endstation" : type;
533
534 PropertyPanel pp = new PropertyPanel(title, typeId)
Simon Huntfb940112015-07-29 18:36:35 -0700535 .id(hostId.toString())
536 .addProp(Properties.MAC, host.mac())
537 .addProp(Properties.IP, host.ipAddresses(), "[\\[\\]]")
538 .addProp(Properties.VLAN, vlan.equals("-1") ? "none" : vlan)
539 .addSeparator()
540 .addProp(Properties.LATITUDE, annot.value(AnnotationKeys.LATITUDE))
541 .addProp(Properties.LONGITUDE, annot.value(AnnotationKeys.LONGITUDE));
Simon Huntb745ca62015-07-28 15:37:11 -0700542
Simon Hunta17fa672015-08-19 18:42:22 -0700543 // Potentially add button descriptors here
Simon Huntb745ca62015-07-28 15:37:11 -0700544 return pp;
Thomas Vachuska329af532015-03-10 02:08:33 -0700545 }
546
Thomas Vachuska329af532015-03-10 02:08:33 -0700547}