blob: f65232eb7cac58b5999d11b207e589a4f7de3fd7 [file] [log] [blame]
Thomas Vachuska7d638d32014-11-07 10:24:43 -08001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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.onlab.onos.gui;
17
Thomas Vachuska9edca302014-11-22 17:06:42 -080018import com.fasterxml.jackson.databind.JsonNode;
Thomas Vachuskadea45ff2014-11-12 18:35:46 -080019import com.fasterxml.jackson.databind.node.ArrayNode;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080020import com.fasterxml.jackson.databind.node.ObjectNode;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080021import org.eclipse.jetty.websocket.WebSocket;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080022import org.onlab.onos.cluster.ClusterEvent;
23import org.onlab.onos.cluster.ClusterEventListener;
24import org.onlab.onos.cluster.ControllerNode;
Thomas Vachuska4830d392014-11-09 17:09:56 -080025import org.onlab.onos.core.ApplicationId;
26import org.onlab.onos.core.CoreService;
Thomas Vachuska9edca302014-11-22 17:06:42 -080027import org.onlab.onos.net.ConnectPoint;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080028import org.onlab.onos.net.Device;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080029import org.onlab.onos.net.Host;
30import org.onlab.onos.net.HostId;
Thomas Vachuska9edca302014-11-22 17:06:42 -080031import org.onlab.onos.net.HostLocation;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080032import org.onlab.onos.net.Link;
33import org.onlab.onos.net.device.DeviceEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080034import org.onlab.onos.net.device.DeviceListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080035import org.onlab.onos.net.flow.DefaultTrafficSelector;
36import org.onlab.onos.net.flow.DefaultTrafficTreatment;
Thomas Vachuska9edca302014-11-22 17:06:42 -080037import org.onlab.onos.net.flow.TrafficSelector;
38import org.onlab.onos.net.flow.TrafficTreatment;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080039import org.onlab.onos.net.host.HostEvent;
40import org.onlab.onos.net.host.HostListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080041import org.onlab.onos.net.intent.HostToHostIntent;
42import org.onlab.onos.net.intent.Intent;
43import org.onlab.onos.net.intent.IntentEvent;
Thomas Vachuska4830d392014-11-09 17:09:56 -080044import org.onlab.onos.net.intent.IntentListener;
Thomas Vachuska9edca302014-11-22 17:06:42 -080045import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080046import org.onlab.onos.net.link.LinkEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080047import org.onlab.onos.net.link.LinkListener;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080048import org.onlab.osgi.ServiceDirectory;
49
50import java.io.IOException;
Thomas Vachuska47635c62014-11-22 01:21:36 -080051import java.util.ArrayList;
52import java.util.Collections;
53import java.util.Comparator;
Thomas Vachuska29617e52014-11-20 03:17:46 -080054import java.util.HashSet;
Thomas Vachuska47635c62014-11-22 01:21:36 -080055import java.util.List;
Thomas Vachuskadea45ff2014-11-12 18:35:46 -080056import java.util.Set;
Thomas Vachuska22e34922014-11-14 00:40:55 -080057import java.util.Timer;
58import java.util.TimerTask;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080059
Thomas Vachuskae7591e52014-11-13 21:31:15 -080060import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080061import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_ADDED;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -080062import static org.onlab.onos.net.DeviceId.deviceId;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080063import static org.onlab.onos.net.HostId.hostId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080064import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED;
Thomas Vachuska4830d392014-11-09 17:09:56 -080065import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080066import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080067
Thomas Vachuska7d638d32014-11-07 10:24:43 -080068/**
69 * Web socket capable of interacting with the GUI topology view.
70 */
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080071public class TopologyViewWebSocket
72 extends TopologyViewMessages
Thomas Vachuskaba5621e2014-11-12 01:47:19 -080073 implements WebSocket.OnTextMessage, WebSocket.OnControl {
74
75 private static final long MAX_AGE_MS = 15000;
76
77 private static final byte PING = 0x9;
78 private static final byte PONG = 0xA;
79 private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
Thomas Vachuska7d638d32014-11-07 10:24:43 -080080
Thomas Vachuska4830d392014-11-09 17:09:56 -080081 private static final String APP_ID = "org.onlab.onos.gui";
Thomas Vachuska4830d392014-11-09 17:09:56 -080082
Thomas Vachuska47635c62014-11-22 01:21:36 -080083 private static final long SUMMARY_FREQUENCY_SEC = 2000;
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080084 private static final long TRAFFIC_FREQUENCY_SEC = 1000;
Thomas Vachuska22e34922014-11-14 00:40:55 -080085
Thomas Vachuska47635c62014-11-22 01:21:36 -080086 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
87 new Comparator<ControllerNode>() {
88 @Override
89 public int compare(ControllerNode o1, ControllerNode o2) {
90 return o1.id().toString().compareTo(o2.id().toString());
91 }
92 };
93
Thomas Vachuska4830d392014-11-09 17:09:56 -080094 private final ApplicationId appId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080095
Thomas Vachuska7d638d32014-11-07 10:24:43 -080096 private Connection connection;
Thomas Vachuskaba5621e2014-11-12 01:47:19 -080097 private FrameConnection control;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080098
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080099 private final ClusterEventListener clusterListener = new InternalClusterListener();
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800100 private final DeviceListener deviceListener = new InternalDeviceListener();
101 private final LinkListener linkListener = new InternalLinkListener();
102 private final HostListener hostListener = new InternalHostListener();
Thomas Vachuska4830d392014-11-09 17:09:56 -0800103 private final IntentListener intentListener = new InternalIntentListener();
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800104
Thomas Vachuska47635c62014-11-22 01:21:36 -0800105 // Timers and objects being monitored
106 private final Timer timer = new Timer("topology-view");
107
108 private TimerTask trafficTask;
109 private ObjectNode trafficEvent;
110
111 private TimerTask summaryTask;
112 private ObjectNode summaryEvent;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800113
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800114 private long lastActive = System.currentTimeMillis();
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800115 private boolean listenersRemoved = false;
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800116
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800117 private TopologyViewIntentFilter intentFilter;
118
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800119 /**
120 * Creates a new web-socket for serving data to GUI topology view.
121 *
122 * @param directory service directory
123 */
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800124 public TopologyViewWebSocket(ServiceDirectory directory) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800125 super(directory);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800126
127 intentFilter = new TopologyViewIntentFilter(intentService, deviceService,
Thomas Vachuska9edca302014-11-22 17:06:42 -0800128 hostService, linkService);
Thomas Vachuska4830d392014-11-09 17:09:56 -0800129 appId = directory.get(CoreService.class).registerApplication(APP_ID);
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800130 }
131
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800132 /**
133 * Issues a close on the connection.
134 */
135 synchronized void close() {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800136 removeListeners();
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800137 if (connection.isOpen()) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800138 connection.close();
139 }
140 }
141
142 /**
143 * Indicates if this connection is idle.
Thomas Vachuska3266abf2014-11-13 09:28:46 -0800144 *
145 * @return true if idle or closed
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800146 */
147 synchronized boolean isIdle() {
148 boolean idle = (System.currentTimeMillis() - lastActive) > MAX_AGE_MS;
149 if (idle || !connection.isOpen()) {
150 return true;
151 }
152 try {
153 control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
154 } catch (IOException e) {
155 log.warn("Unable to send ping message due to: ", e);
156 }
157 return false;
158 }
159
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800160 @Override
161 public void onOpen(Connection connection) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800162 log.info("GUI client connected");
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800163 this.connection = connection;
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800164 this.control = (FrameConnection) connection;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800165 addListeners();
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800166
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800167 sendAllInstances();
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800168 sendAllDevices();
169 sendAllLinks();
Thomas Vachuska4830d392014-11-09 17:09:56 -0800170 sendAllHosts();
171 }
172
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800173 @Override
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800174 public synchronized void onClose(int closeCode, String message) {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800175 removeListeners();
Thomas Vachuska22e34922014-11-14 00:40:55 -0800176 timer.cancel();
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800177 log.info("GUI client disconnected");
178 }
179
180 @Override
181 public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
182 lastActive = System.currentTimeMillis();
183 return true;
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800184 }
185
186 @Override
187 public void onMessage(String data) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800188 lastActive = System.currentTimeMillis();
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800189 try {
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800190 processMessage((ObjectNode) mapper.reader().readTree(data));
Thomas Vachuska4830d392014-11-09 17:09:56 -0800191 } catch (Exception e) {
Thomas Vachuska0f6baee2014-11-11 15:02:32 -0800192 log.warn("Unable to parse GUI request {} due to {}", data, e);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800193 log.warn("Boom!!!!", e);
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800194 }
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800195 }
196
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800197 // Processes the specified event.
198 private void processMessage(ObjectNode event) {
199 String type = string(event, "event", "unknown");
200 if (type.equals("requestDetails")) {
201 requestDetails(event);
202 } else if (type.equals("updateMeta")) {
203 updateMetaUi(event);
Thomas Vachuska9edca302014-11-22 17:06:42 -0800204
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800205 } else if (type.equals("addHostIntent")) {
206 createHostIntent(event);
Thomas Vachuska9edca302014-11-22 17:06:42 -0800207 } else if (type.equals("addMultiSourceIntent")) {
208 createMultiSourceIntent(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800209
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800210 } else if (type.equals("requestTraffic")) {
211 requestTraffic(event);
212 } else if (type.equals("requestAllTraffic")) {
213 requestAllTraffic(event);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800214 } else if (type.equals("requestDeviceLinkFlows")) {
215 requestDeviceLinkFlows(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800216 } else if (type.equals("cancelTraffic")) {
217 cancelTraffic(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800218
219 } else if (type.equals("requestSummary")) {
220 requestSummary(event);
221 } else if (type.equals("cancelSummary")) {
222 cancelSummary(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800223 }
224 }
225
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800226 // Sends the specified data to the client.
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800227 private synchronized void sendMessage(ObjectNode data) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800228 try {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800229 if (connection.isOpen()) {
230 connection.sendMessage(data.toString());
231 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800232 } catch (IOException e) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800233 log.warn("Unable to send message {} to GUI due to {}", data, e);
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800234 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800235 }
236
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800237 // Sends all controller nodes to the client as node-added messages.
238 private void sendAllInstances() {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800239 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
240 Collections.sort(nodes, NODE_COMPARATOR);
241 for (ControllerNode node : nodes) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800242 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800243 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800244 }
245
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800246 // Sends all devices to the client as device-added messages.
247 private void sendAllDevices() {
248 for (Device device : deviceService.getDevices()) {
249 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800250 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800251 }
252
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800253 // Sends all links to the client as link-added messages.
254 private void sendAllLinks() {
255 for (Link link : linkService.getLinks()) {
256 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800257 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800258 }
259
260 // Sends all hosts to the client as host-added messages.
261 private void sendAllHosts() {
262 for (Host host : hostService.getHosts()) {
263 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
264 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800265 }
266
267 // Sends back device or host details.
Thomas Vachuskaf1fae002014-11-11 18:22:02 -0800268 private void requestDetails(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800269 ObjectNode payload = payload(event);
Thomas Vachuskaf1fae002014-11-11 18:22:02 -0800270 String type = string(payload, "class", "unknown");
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800271 long sid = number(event, "sid");
272
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800273 if (type.equals("device")) {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800274 sendMessage(deviceDetails(deviceId(string(payload, "id")), sid));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800275 } else if (type.equals("host")) {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800276 sendMessage(hostDetails(hostId(string(payload, "id")), sid));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800277 }
278 }
279
Thomas Vachuska9edca302014-11-22 17:06:42 -0800280
Thomas Vachuska4830d392014-11-09 17:09:56 -0800281 // Creates host-to-host intent.
282 private void createHostIntent(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800283 ObjectNode payload = payload(event);
284 long id = number(event, "sid");
Thomas Vachuska4830d392014-11-09 17:09:56 -0800285 // TODO: add protection against device ids and non-existent hosts.
286 HostId one = hostId(string(payload, "one"));
287 HostId two = hostId(string(payload, "two"));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800288
Thomas Vachuska9edca302014-11-22 17:06:42 -0800289 HostToHostIntent intent =
290 new HostToHostIntent(appId, one, two,
291 DefaultTrafficSelector.builder().build(),
292 DefaultTrafficTreatment.builder().build());
293 startMonitoring(event);
294 intentService.submit(intent);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800295 }
296
Thomas Vachuska9edca302014-11-22 17:06:42 -0800297 // Creates multi-source-to-single-dest intent.
298 private void createMultiSourceIntent(ObjectNode event) {
299 ObjectNode payload = payload(event);
300 long id = number(event, "sid");
301 // TODO: add protection against device ids and non-existent hosts.
302 Set<HostId> src = getHostIds((ArrayNode) payload.path("src"));
303 HostId dst = hostId(string(payload, "dst"));
304 Host dstHost = hostService.getHost(dst);
305
306 Set<ConnectPoint> ingressPoints = getHostLocations(src);
307
308 // FIXME: clearly, this is not enough
309 TrafficSelector selector = DefaultTrafficSelector.builder()
310 .matchEthDst(dstHost.mac()).build();
311 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
312
313 MultiPointToSinglePointIntent intent =
314 new MultiPointToSinglePointIntent(appId, selector, treatment,
315 ingressPoints, dstHost.location());
316 trafficEvent = event;
317 intentService.submit(intent);
318 }
319
320 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
321 Set<ConnectPoint> points = new HashSet<>();
322 for (HostId hostId : hostIds) {
323 points.add(getHostLocation(hostId));
Thomas Vachuska47635c62014-11-22 01:21:36 -0800324 }
Thomas Vachuska9edca302014-11-22 17:06:42 -0800325 return points;
326 }
327
328 private HostLocation getHostLocation(HostId hostId) {
329 return hostService.getHost(hostId).location();
330 }
331
332 // Produces a list of host ids from the specified JSON array.
333 private Set<HostId> getHostIds(ArrayNode ids) {
334 Set<HostId> hostIds = new HashSet<>();
335 for (JsonNode id : ids) {
336 hostIds.add(hostId(id.asText()));
337 }
338 return hostIds;
339 }
340
341
342 private synchronized long startMonitoring(ObjectNode event) {
343 if (trafficTask != null) {
344 stopMonitoring();
345 }
346 trafficEvent = event;
347 trafficTask = new TrafficMonitor();
348 timer.schedule(trafficTask, TRAFFIC_FREQUENCY_SEC, TRAFFIC_FREQUENCY_SEC);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800349 return number(event, "sid");
350 }
351
352 private synchronized void stopMonitoring() {
353 if (trafficTask != null) {
354 trafficTask.cancel();
355 trafficTask = null;
356 trafficEvent = null;
357 }
358 }
359
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800360 // Subscribes for host traffic messages.
361 private synchronized void requestAllTraffic(ObjectNode event) {
362 ObjectNode payload = payload(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800363 long sid = startMonitoring(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800364 sendMessage(trafficSummaryMessage(sid));
365 }
366
Thomas Vachuska29617e52014-11-20 03:17:46 -0800367 private void requestDeviceLinkFlows(ObjectNode event) {
368 ObjectNode payload = payload(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800369 long sid = startMonitoring(event);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800370
371 // Get the set of selected hosts and their intents.
372 ArrayNode ids = (ArrayNode) payload.path("ids");
373 Set<Host> hosts = new HashSet<>();
374 Set<Device> devices = getDevices(ids);
375
376 // If there is a hover node, include it in the hosts and find intents.
377 String hover = string(payload, "hover");
378 Set<Intent> hoverIntents;
379 if (!isNullOrEmpty(hover)) {
380 addHover(hosts, devices, hover);
381 }
382 sendMessage(flowSummaryMessage(sid, devices));
383 }
384
385
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800386 // Subscribes for host traffic messages.
Thomas Vachuska22e34922014-11-14 00:40:55 -0800387 private synchronized void requestTraffic(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800388 ObjectNode payload = payload(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800389 if (!payload.has("ids")) {
390 return;
391 }
392
Thomas Vachuska47635c62014-11-22 01:21:36 -0800393 long sid = startMonitoring(event);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800394
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800395 // Get the set of selected hosts and their intents.
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800396 ArrayNode ids = (ArrayNode) payload.path("ids");
397 Set<Host> hosts = getHosts(ids);
398 Set<Device> devices = getDevices(ids);
399 Set<Intent> intents = intentFilter.findPathIntents(hosts, devices);
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800400
401 // If there is a hover node, include it in the hosts and find intents.
402 String hover = string(payload, "hover");
403 Set<Intent> hoverIntents;
404 if (!isNullOrEmpty(hover)) {
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800405 addHover(hosts, devices, hover);
406 hoverIntents = intentFilter.findPathIntents(hosts, devices);
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800407 intents.removeAll(hoverIntents);
408
409 // Send an initial message to highlight all links of all monitored intents.
410 sendMessage(trafficMessage(sid,
411 new TrafficClass("primary", hoverIntents),
412 new TrafficClass("secondary", intents)));
413
414 } else {
415 // Send an initial message to highlight all links of all monitored intents.
416 sendMessage(trafficMessage(sid, new TrafficClass("primary", intents)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800417 }
418 }
419
420 // Cancels sending traffic messages.
421 private void cancelTraffic(ObjectNode event) {
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800422 sendMessage(trafficMessage(number(event, "sid")));
Thomas Vachuska47635c62014-11-22 01:21:36 -0800423 stopMonitoring();
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800424 }
425
Thomas Vachuska47635c62014-11-22 01:21:36 -0800426
427 // Subscribes for summary messages.
428 private synchronized void requestSummary(ObjectNode event) {
429 if (summaryTask == null) {
430 summaryEvent = event;
431 summaryTask = new SummaryMonitor();
432 timer.schedule(summaryTask, SUMMARY_FREQUENCY_SEC, SUMMARY_FREQUENCY_SEC);
433 }
434 sendMessage(summmaryMessage(number(event, "sid")));
435 }
436
437 // Cancels sending summary messages.
438 private synchronized void cancelSummary(ObjectNode event) {
439 if (summaryTask != null) {
440 summaryTask.cancel();
441 summaryTask = null;
442 summaryEvent = null;
443 }
444 }
445
446
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800447 // Adds all internal listeners.
448 private void addListeners() {
449 clusterService.addListener(clusterListener);
450 deviceService.addListener(deviceListener);
451 linkService.addListener(linkListener);
452 hostService.addListener(hostListener);
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800453 intentService.addListener(intentListener);
454 }
455
456 // Removes all internal listeners.
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800457 private synchronized void removeListeners() {
458 if (!listenersRemoved) {
459 listenersRemoved = true;
460 clusterService.removeListener(clusterListener);
461 deviceService.removeListener(deviceListener);
462 linkService.removeListener(linkListener);
463 hostService.removeListener(hostListener);
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800464 intentService.removeListener(intentListener);
465 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800466 }
467
468 // Cluster event listener.
469 private class InternalClusterListener implements ClusterEventListener {
470 @Override
471 public void event(ClusterEvent event) {
472 sendMessage(instanceMessage(event));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800473 }
474 }
475
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800476 // Device event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800477 private class InternalDeviceListener implements DeviceListener {
478 @Override
479 public void event(DeviceEvent event) {
480 sendMessage(deviceMessage(event));
481 }
482 }
483
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800484 // Link event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800485 private class InternalLinkListener implements LinkListener {
486 @Override
487 public void event(LinkEvent event) {
488 sendMessage(linkMessage(event));
489 }
490 }
491
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800492 // Host event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800493 private class InternalHostListener implements HostListener {
494 @Override
495 public void event(HostEvent event) {
496 sendMessage(hostMessage(event));
497 }
498 }
499
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800500 // Intent event listener.
Thomas Vachuska4830d392014-11-09 17:09:56 -0800501 private class InternalIntentListener implements IntentListener {
502 @Override
503 public void event(IntentEvent event) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800504 if (trafficEvent != null) {
505 requestTraffic(trafficEvent);
Thomas Vachuska4830d392014-11-09 17:09:56 -0800506 }
507 }
508 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800509
Thomas Vachuska47635c62014-11-22 01:21:36 -0800510 private class TrafficMonitor extends TimerTask {
Thomas Vachuska22e34922014-11-14 00:40:55 -0800511 @Override
512 public void run() {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800513 if (trafficEvent != null) {
514 String type = string(trafficEvent, "event", "unknown");
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800515 if (type.equals("requestAllTraffic")) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800516 requestAllTraffic(trafficEvent);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800517 } else if (type.equals("requestDeviceLinkFlows")) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800518 requestDeviceLinkFlows(trafficEvent);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800519 } else {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800520 requestTraffic(trafficEvent);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800521 }
Thomas Vachuska22e34922014-11-14 00:40:55 -0800522 }
523 }
524 }
Thomas Vachuska47635c62014-11-22 01:21:36 -0800525
526 private class SummaryMonitor extends TimerTask {
527 @Override
528 public void run() {
529 if (summaryEvent != null) {
530 requestSummary(summaryEvent);
531 }
532 }
533 }
534
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800535}
536