blob: 57781de22d408fee07ae5e653407766be8c9c3bc [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 Vachuskae02e11c2014-11-24 16:13:52 -080027import org.onlab.onos.mastership.MastershipEvent;
28import org.onlab.onos.mastership.MastershipListener;
Thomas Vachuska9edca302014-11-22 17:06:42 -080029import org.onlab.onos.net.ConnectPoint;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080030import org.onlab.onos.net.Device;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080031import org.onlab.onos.net.Host;
32import org.onlab.onos.net.HostId;
Thomas Vachuska9edca302014-11-22 17:06:42 -080033import org.onlab.onos.net.HostLocation;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080034import org.onlab.onos.net.Link;
35import org.onlab.onos.net.device.DeviceEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080036import org.onlab.onos.net.device.DeviceListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080037import org.onlab.onos.net.flow.DefaultTrafficSelector;
38import org.onlab.onos.net.flow.DefaultTrafficTreatment;
Thomas Vachuska9edca302014-11-22 17:06:42 -080039import org.onlab.onos.net.flow.TrafficSelector;
40import org.onlab.onos.net.flow.TrafficTreatment;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080041import org.onlab.onos.net.host.HostEvent;
42import org.onlab.onos.net.host.HostListener;
Thomas Vachuska4830d392014-11-09 17:09:56 -080043import org.onlab.onos.net.intent.HostToHostIntent;
44import org.onlab.onos.net.intent.Intent;
45import org.onlab.onos.net.intent.IntentEvent;
Thomas Vachuska4830d392014-11-09 17:09:56 -080046import org.onlab.onos.net.intent.IntentListener;
Thomas Vachuska9edca302014-11-22 17:06:42 -080047import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080048import org.onlab.onos.net.link.LinkEvent;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080049import org.onlab.onos.net.link.LinkListener;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080050import org.onlab.osgi.ServiceDirectory;
Thomas Vachuskae02e11c2014-11-24 16:13:52 -080051import org.onlab.packet.Ethernet;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080052
53import java.io.IOException;
Thomas Vachuska47635c62014-11-22 01:21:36 -080054import java.util.ArrayList;
55import java.util.Collections;
56import java.util.Comparator;
Thomas Vachuska29617e52014-11-20 03:17:46 -080057import java.util.HashSet;
Thomas Vachuska47635c62014-11-22 01:21:36 -080058import java.util.List;
Thomas Vachuskadea45ff2014-11-12 18:35:46 -080059import java.util.Set;
Thomas Vachuska22e34922014-11-14 00:40:55 -080060import java.util.Timer;
61import java.util.TimerTask;
Thomas Vachuska7d638d32014-11-07 10:24:43 -080062
Thomas Vachuskae7591e52014-11-13 21:31:15 -080063import static com.google.common.base.Strings.isNullOrEmpty;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -080064import static org.onlab.onos.cluster.ClusterEvent.Type.INSTANCE_ADDED;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -080065import static org.onlab.onos.net.DeviceId.deviceId;
Thomas Vachuska690e5f62014-11-09 08:26:47 -080066import static org.onlab.onos.net.HostId.hostId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080067import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_ADDED;
Thomas Vachuskae02e11c2014-11-24 16:13:52 -080068import static org.onlab.onos.net.device.DeviceEvent.Type.DEVICE_UPDATED;
Thomas Vachuska4830d392014-11-09 17:09:56 -080069import static org.onlab.onos.net.host.HostEvent.Type.HOST_ADDED;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080070import static org.onlab.onos.net.link.LinkEvent.Type.LINK_ADDED;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080071
Thomas Vachuska7d638d32014-11-07 10:24:43 -080072/**
73 * Web socket capable of interacting with the GUI topology view.
74 */
Thomas Vachuska7c27ad72014-11-14 16:20:10 -080075public class TopologyViewWebSocket
76 extends TopologyViewMessages
Thomas Vachuskaba5621e2014-11-12 01:47:19 -080077 implements WebSocket.OnTextMessage, WebSocket.OnControl {
78
79 private static final long MAX_AGE_MS = 15000;
80
81 private static final byte PING = 0x9;
82 private static final byte PONG = 0xA;
83 private static final byte[] PING_DATA = new byte[]{(byte) 0xde, (byte) 0xad};
Thomas Vachuska7d638d32014-11-07 10:24:43 -080084
Thomas Vachuska4830d392014-11-09 17:09:56 -080085 private static final String APP_ID = "org.onlab.onos.gui";
Thomas Vachuska4830d392014-11-09 17:09:56 -080086
Thomas Vachuskae02e11c2014-11-24 16:13:52 -080087 private static final long SUMMARY_FREQUENCY_SEC = 3000;
88 private static final long TRAFFIC_FREQUENCY_SEC = 1500;
Thomas Vachuska22e34922014-11-14 00:40:55 -080089
Thomas Vachuska47635c62014-11-22 01:21:36 -080090 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
91 new Comparator<ControllerNode>() {
92 @Override
93 public int compare(ControllerNode o1, ControllerNode o2) {
94 return o1.id().toString().compareTo(o2.id().toString());
95 }
96 };
97
Thomas Vachuska4830d392014-11-09 17:09:56 -080098 private final ApplicationId appId;
Thomas Vachuskad472c6e2014-11-07 19:11:05 -080099
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800100 private Connection connection;
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800101 private FrameConnection control;
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800102
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800103 private final ClusterEventListener clusterListener = new InternalClusterListener();
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800104 private final MastershipListener mastershipListener = new InternalMastershipListener();
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800105 private final DeviceListener deviceListener = new InternalDeviceListener();
106 private final LinkListener linkListener = new InternalLinkListener();
107 private final HostListener hostListener = new InternalHostListener();
Thomas Vachuska4830d392014-11-09 17:09:56 -0800108 private final IntentListener intentListener = new InternalIntentListener();
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800109
Thomas Vachuska47635c62014-11-22 01:21:36 -0800110 // Timers and objects being monitored
111 private final Timer timer = new Timer("topology-view");
112
113 private TimerTask trafficTask;
114 private ObjectNode trafficEvent;
115
116 private TimerTask summaryTask;
117 private ObjectNode summaryEvent;
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800118
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800119 private long lastActive = System.currentTimeMillis();
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800120 private boolean listenersRemoved = false;
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800121
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800122 private TopologyViewIntentFilter intentFilter;
123
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800124 /**
125 * Creates a new web-socket for serving data to GUI topology view.
126 *
127 * @param directory service directory
128 */
Thomas Vachuska7c27ad72014-11-14 16:20:10 -0800129 public TopologyViewWebSocket(ServiceDirectory directory) {
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800130 super(directory);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800131
132 intentFilter = new TopologyViewIntentFilter(intentService, deviceService,
Thomas Vachuska9edca302014-11-22 17:06:42 -0800133 hostService, linkService);
Thomas Vachuska4830d392014-11-09 17:09:56 -0800134 appId = directory.get(CoreService.class).registerApplication(APP_ID);
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800135 }
136
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800137 /**
138 * Issues a close on the connection.
139 */
140 synchronized void close() {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800141 removeListeners();
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800142 if (connection.isOpen()) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800143 connection.close();
144 }
145 }
146
147 /**
148 * Indicates if this connection is idle.
Thomas Vachuska3266abf2014-11-13 09:28:46 -0800149 *
150 * @return true if idle or closed
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800151 */
152 synchronized boolean isIdle() {
153 boolean idle = (System.currentTimeMillis() - lastActive) > MAX_AGE_MS;
154 if (idle || !connection.isOpen()) {
155 return true;
156 }
157 try {
158 control.sendControl(PING, PING_DATA, 0, PING_DATA.length);
159 } catch (IOException e) {
160 log.warn("Unable to send ping message due to: ", e);
161 }
162 return false;
163 }
164
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800165 @Override
166 public void onOpen(Connection connection) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800167 log.info("GUI client connected");
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800168 this.connection = connection;
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800169 this.control = (FrameConnection) connection;
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800170 addListeners();
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800171
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800172 sendAllInstances(null);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800173 sendAllDevices();
174 sendAllLinks();
Thomas Vachuska4830d392014-11-09 17:09:56 -0800175 sendAllHosts();
176 }
177
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800178 @Override
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800179 public synchronized void onClose(int closeCode, String message) {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800180 removeListeners();
Thomas Vachuska22e34922014-11-14 00:40:55 -0800181 timer.cancel();
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800182 log.info("GUI client disconnected");
183 }
184
185 @Override
186 public boolean onControl(byte controlCode, byte[] data, int offset, int length) {
187 lastActive = System.currentTimeMillis();
188 return true;
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800189 }
190
191 @Override
192 public void onMessage(String data) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800193 lastActive = System.currentTimeMillis();
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800194 try {
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800195 processMessage((ObjectNode) mapper.reader().readTree(data));
Thomas Vachuska4830d392014-11-09 17:09:56 -0800196 } catch (Exception e) {
Thomas Vachuska0f6baee2014-11-11 15:02:32 -0800197 log.warn("Unable to parse GUI request {} due to {}", data, e);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800198 log.warn("Boom!!!!", e);
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800199 }
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800200 }
201
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800202 // Processes the specified event.
203 private void processMessage(ObjectNode event) {
204 String type = string(event, "event", "unknown");
205 if (type.equals("requestDetails")) {
206 requestDetails(event);
207 } else if (type.equals("updateMeta")) {
208 updateMetaUi(event);
Thomas Vachuska9edca302014-11-22 17:06:42 -0800209
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800210 } else if (type.equals("addHostIntent")) {
211 createHostIntent(event);
Thomas Vachuska9edca302014-11-22 17:06:42 -0800212 } else if (type.equals("addMultiSourceIntent")) {
213 createMultiSourceIntent(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800214
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800215 } else if (type.equals("requestTraffic")) {
216 requestTraffic(event);
217 } else if (type.equals("requestAllTraffic")) {
218 requestAllTraffic(event);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800219 } else if (type.equals("requestDeviceLinkFlows")) {
220 requestDeviceLinkFlows(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800221 } else if (type.equals("cancelTraffic")) {
222 cancelTraffic(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800223
224 } else if (type.equals("requestSummary")) {
225 requestSummary(event);
226 } else if (type.equals("cancelSummary")) {
227 cancelSummary(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800228 }
229 }
230
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800231 // Sends the specified data to the client.
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800232 private synchronized void sendMessage(ObjectNode data) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800233 try {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800234 if (connection.isOpen()) {
235 connection.sendMessage(data.toString());
236 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800237 } catch (IOException e) {
Thomas Vachuskaba5621e2014-11-12 01:47:19 -0800238 log.warn("Unable to send message {} to GUI due to {}", data, e);
Thomas Vachuskad1be50d2014-11-08 16:10:20 -0800239 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800240 }
241
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800242 // Sends all controller nodes to the client as node-added messages.
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800243 private void sendAllInstances(String messageType) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800244 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
245 Collections.sort(nodes, NODE_COMPARATOR);
246 for (ControllerNode node : nodes) {
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800247 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
248 messageType));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800249 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800250 }
251
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800252 // Sends all devices to the client as device-added messages.
253 private void sendAllDevices() {
254 for (Device device : deviceService.getDevices()) {
255 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800256 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800257 }
258
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800259 // Sends all links to the client as link-added messages.
260 private void sendAllLinks() {
261 for (Link link : linkService.getLinks()) {
262 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800263 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800264 }
265
266 // Sends all hosts to the client as host-added messages.
267 private void sendAllHosts() {
268 for (Host host : hostService.getHosts()) {
269 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
270 }
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800271 }
272
273 // Sends back device or host details.
Thomas Vachuskaf1fae002014-11-11 18:22:02 -0800274 private void requestDetails(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800275 ObjectNode payload = payload(event);
Thomas Vachuskaf1fae002014-11-11 18:22:02 -0800276 String type = string(payload, "class", "unknown");
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800277 long sid = number(event, "sid");
278
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800279 if (type.equals("device")) {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800280 sendMessage(deviceDetails(deviceId(string(payload, "id")), sid));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800281 } else if (type.equals("host")) {
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800282 sendMessage(hostDetails(hostId(string(payload, "id")), sid));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800283 }
284 }
285
Thomas Vachuska9edca302014-11-22 17:06:42 -0800286
Thomas Vachuska4830d392014-11-09 17:09:56 -0800287 // Creates host-to-host intent.
288 private void createHostIntent(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800289 ObjectNode payload = payload(event);
290 long id = number(event, "sid");
Thomas Vachuska4830d392014-11-09 17:09:56 -0800291 // TODO: add protection against device ids and non-existent hosts.
292 HostId one = hostId(string(payload, "one"));
293 HostId two = hostId(string(payload, "two"));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800294
Thomas Vachuska9edca302014-11-22 17:06:42 -0800295 HostToHostIntent intent =
296 new HostToHostIntent(appId, one, two,
297 DefaultTrafficSelector.builder().build(),
298 DefaultTrafficTreatment.builder().build());
299 startMonitoring(event);
300 intentService.submit(intent);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800301 }
302
Thomas Vachuska9edca302014-11-22 17:06:42 -0800303 // Creates multi-source-to-single-dest intent.
304 private void createMultiSourceIntent(ObjectNode event) {
305 ObjectNode payload = payload(event);
306 long id = number(event, "sid");
307 // TODO: add protection against device ids and non-existent hosts.
308 Set<HostId> src = getHostIds((ArrayNode) payload.path("src"));
309 HostId dst = hostId(string(payload, "dst"));
310 Host dstHost = hostService.getHost(dst);
311
312 Set<ConnectPoint> ingressPoints = getHostLocations(src);
313
314 // FIXME: clearly, this is not enough
315 TrafficSelector selector = DefaultTrafficSelector.builder()
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800316 .matchEthType(Ethernet.TYPE_IPV4)
Thomas Vachuska9edca302014-11-22 17:06:42 -0800317 .matchEthDst(dstHost.mac()).build();
318 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
319
320 MultiPointToSinglePointIntent intent =
321 new MultiPointToSinglePointIntent(appId, selector, treatment,
322 ingressPoints, dstHost.location());
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800323 startMonitoring(event);
Thomas Vachuska9edca302014-11-22 17:06:42 -0800324 intentService.submit(intent);
325 }
326
327 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
328 Set<ConnectPoint> points = new HashSet<>();
329 for (HostId hostId : hostIds) {
330 points.add(getHostLocation(hostId));
Thomas Vachuska47635c62014-11-22 01:21:36 -0800331 }
Thomas Vachuska9edca302014-11-22 17:06:42 -0800332 return points;
333 }
334
335 private HostLocation getHostLocation(HostId hostId) {
336 return hostService.getHost(hostId).location();
337 }
338
339 // Produces a list of host ids from the specified JSON array.
340 private Set<HostId> getHostIds(ArrayNode ids) {
341 Set<HostId> hostIds = new HashSet<>();
342 for (JsonNode id : ids) {
343 hostIds.add(hostId(id.asText()));
344 }
345 return hostIds;
346 }
347
348
349 private synchronized long startMonitoring(ObjectNode event) {
350 if (trafficTask != null) {
351 stopMonitoring();
352 }
353 trafficEvent = event;
354 trafficTask = new TrafficMonitor();
355 timer.schedule(trafficTask, TRAFFIC_FREQUENCY_SEC, TRAFFIC_FREQUENCY_SEC);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800356 return number(event, "sid");
357 }
358
359 private synchronized void stopMonitoring() {
360 if (trafficTask != null) {
361 trafficTask.cancel();
362 trafficTask = null;
363 trafficEvent = null;
364 }
365 }
366
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800367 // Subscribes for host traffic messages.
368 private synchronized void requestAllTraffic(ObjectNode event) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800369 long sid = startMonitoring(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800370 sendMessage(trafficSummaryMessage(sid));
371 }
372
Thomas Vachuska29617e52014-11-20 03:17:46 -0800373 private void requestDeviceLinkFlows(ObjectNode event) {
374 ObjectNode payload = payload(event);
Thomas Vachuska47635c62014-11-22 01:21:36 -0800375 long sid = startMonitoring(event);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800376
377 // Get the set of selected hosts and their intents.
378 ArrayNode ids = (ArrayNode) payload.path("ids");
379 Set<Host> hosts = new HashSet<>();
380 Set<Device> devices = getDevices(ids);
381
382 // If there is a hover node, include it in the hosts and find intents.
383 String hover = string(payload, "hover");
Thomas Vachuska29617e52014-11-20 03:17:46 -0800384 if (!isNullOrEmpty(hover)) {
385 addHover(hosts, devices, hover);
386 }
387 sendMessage(flowSummaryMessage(sid, devices));
388 }
389
390
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800391 // Subscribes for host traffic messages.
Thomas Vachuska22e34922014-11-14 00:40:55 -0800392 private synchronized void requestTraffic(ObjectNode event) {
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800393 ObjectNode payload = payload(event);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800394 if (!payload.has("ids")) {
395 return;
396 }
397
Thomas Vachuska47635c62014-11-22 01:21:36 -0800398 long sid = startMonitoring(event);
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800399
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800400 // Get the set of selected hosts and their intents.
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800401 ArrayNode ids = (ArrayNode) payload.path("ids");
402 Set<Host> hosts = getHosts(ids);
403 Set<Device> devices = getDevices(ids);
404 Set<Intent> intents = intentFilter.findPathIntents(hosts, devices);
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800405
406 // If there is a hover node, include it in the hosts and find intents.
407 String hover = string(payload, "hover");
408 Set<Intent> hoverIntents;
409 if (!isNullOrEmpty(hover)) {
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800410 addHover(hosts, devices, hover);
411 hoverIntents = intentFilter.findPathIntents(hosts, devices);
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800412 intents.removeAll(hoverIntents);
413
414 // Send an initial message to highlight all links of all monitored intents.
415 sendMessage(trafficMessage(sid,
416 new TrafficClass("primary", hoverIntents),
417 new TrafficClass("secondary", intents)));
418
419 } else {
420 // Send an initial message to highlight all links of all monitored intents.
421 sendMessage(trafficMessage(sid, new TrafficClass("primary", intents)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800422 }
423 }
424
425 // Cancels sending traffic messages.
426 private void cancelTraffic(ObjectNode event) {
Thomas Vachuskae7591e52014-11-13 21:31:15 -0800427 sendMessage(trafficMessage(number(event, "sid")));
Thomas Vachuska47635c62014-11-22 01:21:36 -0800428 stopMonitoring();
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800429 }
430
Thomas Vachuska47635c62014-11-22 01:21:36 -0800431
432 // Subscribes for summary messages.
433 private synchronized void requestSummary(ObjectNode event) {
434 if (summaryTask == null) {
435 summaryEvent = event;
436 summaryTask = new SummaryMonitor();
437 timer.schedule(summaryTask, SUMMARY_FREQUENCY_SEC, SUMMARY_FREQUENCY_SEC);
438 }
439 sendMessage(summmaryMessage(number(event, "sid")));
440 }
441
442 // Cancels sending summary messages.
443 private synchronized void cancelSummary(ObjectNode event) {
444 if (summaryTask != null) {
445 summaryTask.cancel();
446 summaryTask = null;
447 summaryEvent = null;
448 }
449 }
450
451
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800452 // Adds all internal listeners.
453 private void addListeners() {
454 clusterService.addListener(clusterListener);
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800455 mastershipService.addListener(mastershipListener);
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800456 deviceService.addListener(deviceListener);
457 linkService.addListener(linkListener);
458 hostService.addListener(hostListener);
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800459 intentService.addListener(intentListener);
460 }
461
462 // Removes all internal listeners.
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800463 private synchronized void removeListeners() {
464 if (!listenersRemoved) {
465 listenersRemoved = true;
466 clusterService.removeListener(clusterListener);
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800467 mastershipService.removeListener(mastershipListener);
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800468 deviceService.removeListener(deviceListener);
469 linkService.removeListener(linkListener);
470 hostService.removeListener(hostListener);
Thomas Vachuskadea45ff2014-11-12 18:35:46 -0800471 intentService.removeListener(intentListener);
472 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800473 }
474
475 // Cluster event listener.
476 private class InternalClusterListener implements ClusterEventListener {
477 @Override
478 public void event(ClusterEvent event) {
Thomas Vachuskae02e11c2014-11-24 16:13:52 -0800479 sendMessage(instanceMessage(event, null));
480 }
481 }
482
483 // Mastership change listener
484 private class InternalMastershipListener implements MastershipListener {
485 @Override
486 public void event(MastershipEvent event) {
487 sendAllInstances("updateInstance");
488 Device device = deviceService.getDevice(event.subject());
489 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800490 }
491 }
492
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800493 // Device event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800494 private class InternalDeviceListener implements DeviceListener {
495 @Override
496 public void event(DeviceEvent event) {
497 sendMessage(deviceMessage(event));
498 }
499 }
500
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800501 // Link event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800502 private class InternalLinkListener implements LinkListener {
503 @Override
504 public void event(LinkEvent event) {
505 sendMessage(linkMessage(event));
506 }
507 }
508
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800509 // Host event listener.
Thomas Vachuska690e5f62014-11-09 08:26:47 -0800510 private class InternalHostListener implements HostListener {
511 @Override
512 public void event(HostEvent event) {
513 sendMessage(hostMessage(event));
514 }
515 }
516
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800517 // Intent event listener.
Thomas Vachuska4830d392014-11-09 17:09:56 -0800518 private class InternalIntentListener implements IntentListener {
519 @Override
520 public void event(IntentEvent event) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800521 if (trafficEvent != null) {
522 requestTraffic(trafficEvent);
Thomas Vachuska4830d392014-11-09 17:09:56 -0800523 }
524 }
525 }
Thomas Vachuskaa7c3dd12014-11-11 09:10:19 -0800526
Thomas Vachuska47635c62014-11-22 01:21:36 -0800527 private class TrafficMonitor extends TimerTask {
Thomas Vachuska22e34922014-11-14 00:40:55 -0800528 @Override
529 public void run() {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800530 if (trafficEvent != null) {
531 String type = string(trafficEvent, "event", "unknown");
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800532 if (type.equals("requestAllTraffic")) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800533 requestAllTraffic(trafficEvent);
Thomas Vachuska29617e52014-11-20 03:17:46 -0800534 } else if (type.equals("requestDeviceLinkFlows")) {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800535 requestDeviceLinkFlows(trafficEvent);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800536 } else {
Thomas Vachuska47635c62014-11-22 01:21:36 -0800537 requestTraffic(trafficEvent);
Thomas Vachuska5fedb7a2014-11-20 00:55:08 -0800538 }
Thomas Vachuska22e34922014-11-14 00:40:55 -0800539 }
540 }
541 }
Thomas Vachuska47635c62014-11-22 01:21:36 -0800542
543 private class SummaryMonitor extends TimerTask {
544 @Override
545 public void run() {
546 if (summaryEvent != null) {
547 requestSummary(summaryEvent);
548 }
549 }
550 }
551
Thomas Vachuska7d638d32014-11-07 10:24:43 -0800552}
553