blob: 700e57e396e6e8b3251d979756bdd76639085c72 [file] [log] [blame]
Thomas Vachuska329af532015-03-10 02:08:33 -07001/*
2 * Copyright 2015 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.onosproject.ui.impl;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.ImmutableSet;
22import org.onlab.osgi.ServiceDirectory;
23import org.onlab.util.AbstractAccumulator;
24import org.onlab.util.Accumulator;
25import org.onosproject.cluster.ClusterEvent;
26import org.onosproject.cluster.ClusterEventListener;
27import org.onosproject.cluster.ControllerNode;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070030import org.onosproject.core.DefaultApplicationId;
Thomas Vachuska329af532015-03-10 02:08:33 -070031import org.onosproject.event.Event;
32import org.onosproject.mastership.MastershipAdminService;
33import org.onosproject.mastership.MastershipEvent;
34import org.onosproject.mastership.MastershipListener;
35import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.Device;
Simon Huntde99e0b2015-10-23 18:54:06 -070037import org.onosproject.net.DeviceId;
Thomas Vachuska329af532015-03-10 02:08:33 -070038import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.HostLocation;
41import org.onosproject.net.Link;
42import org.onosproject.net.device.DeviceEvent;
43import org.onosproject.net.device.DeviceListener;
44import org.onosproject.net.flow.DefaultTrafficSelector;
45import org.onosproject.net.flow.DefaultTrafficTreatment;
46import org.onosproject.net.flow.FlowRuleEvent;
47import org.onosproject.net.flow.FlowRuleListener;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
50import org.onosproject.net.host.HostEvent;
51import org.onosproject.net.host.HostListener;
52import org.onosproject.net.intent.HostToHostIntent;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070053import org.onosproject.net.intent.Intent;
Thomas Vachuska329af532015-03-10 02:08:33 -070054import org.onosproject.net.intent.IntentEvent;
55import org.onosproject.net.intent.IntentListener;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070056import org.onosproject.net.intent.Key;
Thomas Vachuska329af532015-03-10 02:08:33 -070057import org.onosproject.net.intent.MultiPointToSinglePointIntent;
58import org.onosproject.net.link.LinkEvent;
59import org.onosproject.net.link.LinkListener;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070060import org.onosproject.ui.JsonUtils;
Simon Huntd2747a02015-04-30 22:41:16 -070061import org.onosproject.ui.RequestHandler;
Thomas Vachuska329af532015-03-10 02:08:33 -070062import org.onosproject.ui.UiConnection;
Simon Hunt4fc86852015-08-20 17:57:52 -070063import org.onosproject.ui.impl.TrafficMonitor.Mode;
Simon Hunta17fa672015-08-19 18:42:22 -070064import org.onosproject.ui.topo.Highlights;
Simon Huntd3ceffa2015-08-25 12:44:35 -070065import org.onosproject.ui.topo.NodeSelection;
Simon Hunt0af1ec32015-07-24 12:17:55 -070066import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070067
68import java.util.ArrayList;
Simon Huntd2747a02015-04-30 22:41:16 -070069import java.util.Collection;
Thomas Vachuska329af532015-03-10 02:08:33 -070070import java.util.Collections;
71import java.util.Comparator;
72import java.util.HashSet;
73import java.util.List;
74import java.util.Set;
75import java.util.Timer;
76import java.util.TimerTask;
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070077import java.util.concurrent.ExecutorService;
Thomas Vachuska329af532015-03-10 02:08:33 -070078
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070079import static java.util.concurrent.Executors.newSingleThreadExecutor;
80import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska329af532015-03-10 02:08:33 -070081import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
82import static org.onosproject.net.DeviceId.deviceId;
83import static org.onosproject.net.HostId.hostId;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070084import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
85import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
86import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
Thomas Vachuska329af532015-03-10 02:08:33 -070087import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
88import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntd3ceffa2015-08-25 12:44:35 -070089import static org.onosproject.ui.JsonUtils.envelope;
Simon Hunt52560662015-08-27 22:46:44 -070090import static org.onosproject.ui.topo.TopoJson.highlightsMessage;
91import static org.onosproject.ui.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070092
93/**
94 * Web socket capable of interacting with the GUI topology view.
95 */
96public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
97
Simon Huntb745ca62015-07-28 15:37:11 -070098 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -070099 private static final String REQ_DETAILS = "requestDetails";
100 private static final String UPDATE_META = "updateMeta";
101 private static final String ADD_HOST_INTENT = "addHostIntent";
102 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
103 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
104 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
105 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
106 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700107 private static final String SEL_INTENT = "selectIntent";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700108 private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
109 private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700110 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
111 private static final String CANCEL_TRAFFIC = "cancelTraffic";
112 private static final String REQ_SUMMARY = "requestSummary";
113 private static final String CANCEL_SUMMARY = "cancelSummary";
114 private static final String EQ_MASTERS = "equalizeMasters";
115 private static final String SPRITE_LIST_REQ = "spriteListRequest";
116 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
117 private static final String TOPO_START = "topoStart";
Simon Hunt732bb2e2015-05-13 18:32:16 -0700118 private static final String TOPO_HEARTBEAT = "topoHeartbeat";
Simon Hunte05cae42015-07-23 17:35:24 -0700119 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700120 private static final String TOPO_STOP = "topoStop";
121
Simon Huntb745ca62015-07-28 15:37:11 -0700122 // outgoing event types
123 private static final String SHOW_SUMMARY = "showSummary";
124 private static final String SHOW_DETAILS = "showDetails";
125 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
126 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
127 private static final String UPDATE_INSTANCE = "updateInstance";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700128 private static final String TOPO_START_DONE = "topoStartDone";
Simon Huntb745ca62015-07-28 15:37:11 -0700129
130 // fields
131 private static final String ID = "id";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700132 private static final String KEY = "key";
133 private static final String APP_ID = "appId";
134 private static final String APP_NAME = "appName";
Simon Huntb745ca62015-07-28 15:37:11 -0700135 private static final String DEVICE = "device";
136 private static final String HOST = "host";
137 private static final String CLASS = "class";
138 private static final String UNKNOWN = "unknown";
139 private static final String ONE = "one";
140 private static final String TWO = "two";
141 private static final String SRC = "src";
142 private static final String DST = "dst";
143 private static final String DATA = "data";
144 private static final String NAME = "name";
145 private static final String NAMES = "names";
146 private static final String ACTIVATE = "activate";
147 private static final String DEACTIVATE = "deactivate";
Simon Huntb745ca62015-07-28 15:37:11 -0700148
Simon Huntd2747a02015-04-30 22:41:16 -0700149
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700150 private static final String MY_APP_ID = "org.onosproject.gui";
Thomas Vachuska329af532015-03-10 02:08:33 -0700151
Simon Hunta17fa672015-08-19 18:42:22 -0700152 private static final long TRAFFIC_PERIOD = 5000;
153 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700154
155 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Thomas Vachuskac0fe09a2015-05-21 12:56:22 -0700156 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700157
158
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700159 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700160
161 private static final int MAX_EVENTS = 1000;
162 private static final int MAX_BATCH_MS = 5000;
163 private static final int MAX_IDLE_MS = 1000;
164
165 private ApplicationId appId;
166
167 private final ClusterEventListener clusterListener = new InternalClusterListener();
168 private final MastershipListener mastershipListener = new InternalMastershipListener();
169 private final DeviceListener deviceListener = new InternalDeviceListener();
170 private final LinkListener linkListener = new InternalLinkListener();
171 private final HostListener hostListener = new InternalHostListener();
172 private final IntentListener intentListener = new InternalIntentListener();
173 private final FlowRuleListener flowListener = new InternalFlowListener();
174
175 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700176 private final ExecutorService msgSender =
177 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender"));
Thomas Vachuska329af532015-03-10 02:08:33 -0700178
Simon Hunta17fa672015-08-19 18:42:22 -0700179 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700180 private TrafficMonitor traffic;
Thomas Vachuska329af532015-03-10 02:08:33 -0700181
Simon Huntd2747a02015-04-30 22:41:16 -0700182 private TimerTask summaryTask = null;
183 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700184
185 private boolean listenersRemoved = false;
186
Thomas Vachuska329af532015-03-10 02:08:33 -0700187
188 @Override
189 public void init(UiConnection connection, ServiceDirectory directory) {
190 super.init(connection, directory);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700191 appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
Simon Hunt4fc86852015-08-20 17:57:52 -0700192 traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700193 }
194
195 @Override
196 public void destroy() {
197 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700198 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700199 super.destroy();
200 }
201
Thomas Vachuska329af532015-03-10 02:08:33 -0700202 @Override
Simon Huntda580882015-05-12 20:58:18 -0700203 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700204 return ImmutableSet.of(
205 new TopoStart(),
Simon Hunt732bb2e2015-05-13 18:32:16 -0700206 new TopoHeartbeat(),
Simon Hunte05cae42015-07-23 17:35:24 -0700207 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700208 new TopoStop(),
209 new ReqSummary(),
210 new CancelSummary(),
211 new SpriteListReq(),
212 new SpriteDataReq(),
213 new RequestDetails(),
214 new UpdateMeta(),
215 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700216
Simon Huntd2747a02015-04-30 22:41:16 -0700217 // TODO: migrate traffic related to separate app
218 new AddHostIntent(),
219 new AddMultiSourceIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700220
221 new ReqAllFlowTraffic(),
222 new ReqAllPortTraffic(),
223 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700224 new ReqRelatedIntents(),
225 new ReqNextIntent(),
226 new ReqPrevIntent(),
227 new ReqSelectedIntentTraffic(),
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700228 new SelIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700229
Simon Huntd2747a02015-04-30 22:41:16 -0700230 new CancelTraffic()
231 );
232 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700233
Simon Hunte05cae42015-07-23 17:35:24 -0700234 /**
235 * Injects the topology overlay cache.
236 *
237 * @param overlayCache injected cache
238 */
239 void setOverlayCache(TopoOverlayCache overlayCache) {
240 this.overlayCache = overlayCache;
241 }
242
Simon Huntd2747a02015-04-30 22:41:16 -0700243 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700244
Simon Huntd2747a02015-04-30 22:41:16 -0700245 private final class TopoStart extends RequestHandler {
246 private TopoStart() {
247 super(TOPO_START);
248 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700249
Simon Huntd2747a02015-04-30 22:41:16 -0700250 @Override
251 public void process(long sid, ObjectNode payload) {
252 addListeners();
253 sendAllInstances(null);
254 sendAllDevices();
255 sendAllLinks();
256 sendAllHosts();
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700257 sendTopoStartDone();
Thomas Vachuska329af532015-03-10 02:08:33 -0700258 }
259 }
260
Simon Hunt732bb2e2015-05-13 18:32:16 -0700261 private final class TopoHeartbeat extends RequestHandler {
262 private TopoHeartbeat() {
263 super(TOPO_HEARTBEAT);
264 }
265
266 @Override
267 public void process(long sid, ObjectNode payload) {
268 // place holder for now
269 }
270 }
271
Simon Hunte05cae42015-07-23 17:35:24 -0700272 private final class TopoSelectOverlay extends RequestHandler {
273 private TopoSelectOverlay() {
274 super(TOPO_SELECT_OVERLAY);
275 }
276
277 @Override
278 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700279 String deact = string(payload, DEACTIVATE);
280 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700281 overlayCache.switchOverlay(deact, act);
282 }
283 }
284
Simon Huntd2747a02015-04-30 22:41:16 -0700285 private final class TopoStop extends RequestHandler {
286 private TopoStop() {
287 super(TOPO_STOP);
288 }
289
290 @Override
291 public void process(long sid, ObjectNode payload) {
Simon Hunt1ad59272015-11-10 15:23:21 -0800292 removeListeners();
Simon Huntd2747a02015-04-30 22:41:16 -0700293 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700294 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700295 }
296 }
297
298 private final class ReqSummary extends RequestHandler {
299 private ReqSummary() {
300 super(REQ_SUMMARY);
301 }
302
303 @Override
304 public void process(long sid, ObjectNode payload) {
305 requestSummary(sid);
306 startSummaryMonitoring();
307 }
308 }
309
310 private final class CancelSummary extends RequestHandler {
311 private CancelSummary() {
312 super(CANCEL_SUMMARY);
313 }
314
315 @Override
316 public void process(long sid, ObjectNode payload) {
317 stopSummaryMonitoring();
318 }
319 }
320
321 private final class SpriteListReq extends RequestHandler {
322 private SpriteListReq() {
323 super(SPRITE_LIST_REQ);
324 }
325
326 @Override
327 public void process(long sid, ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700328 ObjectNode root = objectNode();
329 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700330 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700331 root.set(NAMES, names);
332 sendMessage(SPRITE_LIST_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700333 }
334 }
335
336 private final class SpriteDataReq extends RequestHandler {
337 private SpriteDataReq() {
338 super(SPRITE_DATA_REQ);
339 }
340
341 @Override
342 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700343 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700344 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700345 root.set(DATA, get(SpriteService.class).get(name));
346 sendMessage(SPRITE_DATA_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700347 }
348 }
349
350 private final class RequestDetails extends RequestHandler {
351 private RequestDetails() {
352 super(REQ_DETAILS);
353 }
354
355 @Override
356 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700357 String type = string(payload, CLASS, UNKNOWN);
358 String id = string(payload, ID);
359 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700360
Simon Huntb745ca62015-07-28 15:37:11 -0700361 if (type.equals(DEVICE)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700362 DeviceId did = deviceId(id);
363 pp = deviceDetails(did, sid);
364 overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
Simon Huntb745ca62015-07-28 15:37:11 -0700365 } else if (type.equals(HOST)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700366 HostId hid = hostId(id);
367 pp = hostDetails(hid, sid);
368 overlayCache.currentOverlay().modifyHostDetails(pp, hid);
Simon Huntd2747a02015-04-30 22:41:16 -0700369 }
Simon Huntb745ca62015-07-28 15:37:11 -0700370
Simon Huntd3ceffa2015-08-25 12:44:35 -0700371 sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
Simon Huntd2747a02015-04-30 22:41:16 -0700372 }
373 }
374
375 private final class UpdateMeta extends RequestHandler {
376 private UpdateMeta() {
377 super(UPDATE_META);
378 }
379
380 @Override
381 public void process(long sid, ObjectNode payload) {
382 updateMetaUi(payload);
383 }
384 }
385
386 private final class EqMasters extends RequestHandler {
387 private EqMasters() {
388 super(EQ_MASTERS);
389 }
390
391 @Override
392 public void process(long sid, ObjectNode payload) {
393 directory.get(MastershipAdminService.class).balanceRoles();
394 }
395 }
396
Simon Hunta17fa672015-08-19 18:42:22 -0700397
398 // ========= -----------------------------------------------------------------
399
Simon Huntd2747a02015-04-30 22:41:16 -0700400 // === TODO: move traffic related classes to traffic app
401
402 private final class AddHostIntent extends RequestHandler {
403 private AddHostIntent() {
404 super(ADD_HOST_INTENT);
405 }
406
407 @Override
408 public void process(long sid, ObjectNode payload) {
409 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700410 HostId one = hostId(string(payload, ONE));
411 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700412
413 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700414 .appId(appId)
415 .one(one)
416 .two(two)
417 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700418
419 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700420 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
421 traffic.monitor(intent);
422 }
Simon Huntd2747a02015-04-30 22:41:16 -0700423 }
424 }
425
426 private final class AddMultiSourceIntent extends RequestHandler {
427 private AddMultiSourceIntent() {
428 super(ADD_MULTI_SRC_INTENT);
429 }
430
431 @Override
432 public void process(long sid, ObjectNode payload) {
433 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700434 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
435 HostId dst = hostId(string(payload, DST));
Simon Huntd2747a02015-04-30 22:41:16 -0700436 Host dstHost = hostService.getHost(dst);
437
438 Set<ConnectPoint> ingressPoints = getHostLocations(src);
439
440 // FIXME: clearly, this is not enough
441 TrafficSelector selector = DefaultTrafficSelector.builder()
442 .matchEthDst(dstHost.mac()).build();
443 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
444
445 MultiPointToSinglePointIntent intent =
446 MultiPointToSinglePointIntent.builder()
447 .appId(appId)
448 .selector(selector)
449 .treatment(treatment)
450 .ingressPoints(ingressPoints)
451 .egressPoint(dstHost.location())
452 .build();
453
454 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700455 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
456 traffic.monitor(intent);
457 }
Simon Huntd2747a02015-04-30 22:41:16 -0700458 }
459 }
460
Simon Hunta17fa672015-08-19 18:42:22 -0700461 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700462
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700463 private final class ReqAllFlowTraffic extends RequestHandler {
464 private ReqAllFlowTraffic() {
465 super(REQ_ALL_FLOW_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700466 }
467
468 @Override
469 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700470 traffic.monitor(Mode.ALL_FLOW_TRAFFIC);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700471 }
472 }
473
474 private final class ReqAllPortTraffic extends RequestHandler {
475 private ReqAllPortTraffic() {
476 super(REQ_ALL_PORT_TRAFFIC);
477 }
478
479 @Override
480 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700481 traffic.monitor(Mode.ALL_PORT_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700482 }
483 }
484
485 private final class ReqDevLinkFlows extends RequestHandler {
486 private ReqDevLinkFlows() {
487 super(REQ_DEV_LINK_FLOWS);
488 }
489
490 @Override
491 public void process(long sid, ObjectNode payload) {
Simon Hunta17fa672015-08-19 18:42:22 -0700492 NodeSelection nodeSelection =
493 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700494 traffic.monitor(Mode.DEV_LINK_FLOWS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700495 }
496 }
497
498 private final class ReqRelatedIntents extends RequestHandler {
499 private ReqRelatedIntents() {
500 super(REQ_RELATED_INTENTS);
501 }
502
503 @Override
504 public void process(long sid, ObjectNode payload) {
505 NodeSelection nodeSelection =
506 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700507 traffic.monitor(Mode.RELATED_INTENTS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700508 }
509 }
510
511 private final class ReqNextIntent extends RequestHandler {
512 private ReqNextIntent() {
513 super(REQ_NEXT_INTENT);
514 }
515
516 @Override
517 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700518 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700519 }
520 }
521
522 private final class ReqPrevIntent extends RequestHandler {
523 private ReqPrevIntent() {
524 super(REQ_PREV_INTENT);
525 }
526
527 @Override
528 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700529 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700530 }
531 }
532
533 private final class ReqSelectedIntentTraffic extends RequestHandler {
534 private ReqSelectedIntentTraffic() {
535 super(REQ_SEL_INTENT_TRAFFIC);
536 }
537
538 @Override
539 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700540 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700541 }
542 }
543
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700544 private final class SelIntent extends RequestHandler {
545 private SelIntent() {
546 super(SEL_INTENT);
547 }
548
549 @Override
550 public void process(long sid, ObjectNode payload) {
551 int appId = Integer.parseInt(string(payload, APP_ID));
552 String appName = string(payload, APP_NAME);
553 ApplicationId applicId = new DefaultApplicationId(appId, appName);
554 long intentKey = Long.decode(string(payload, KEY));
555
556 Key key = Key.of(intentKey, applicId);
557 log.debug("Attempting to select intent key={}", key);
558
559 Intent intent = intentService.getIntent(key);
560 if (intent == null) {
561 log.debug("no such intent found!");
562 } else {
563 log.debug("starting to monitor intent {}", key);
564 traffic.monitor(intent);
565 }
566 }
567 }
568
Simon Huntd2747a02015-04-30 22:41:16 -0700569 private final class CancelTraffic extends RequestHandler {
570 private CancelTraffic() {
571 super(CANCEL_TRAFFIC);
572 }
573
574 @Override
575 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700576 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700577 }
578 }
579
580 //=======================================================================
581
Simon Hunta17fa672015-08-19 18:42:22 -0700582 // Converts highlights to JSON format and sends the message to the client
583 protected void sendHighlights(Highlights highlights) {
Simon Hunt52560662015-08-27 22:46:44 -0700584 sendMessage(highlightsMessage(highlights));
Thomas Vachuska329af532015-03-10 02:08:33 -0700585 }
586
Simon Huntd2747a02015-04-30 22:41:16 -0700587 // Subscribes for summary messages.
588 private synchronized void requestSummary(long sid) {
Simon Hunt0af1ec32015-07-24 12:17:55 -0700589 PropertyPanel pp = summmaryMessage(sid);
590 overlayCache.currentOverlay().modifySummary(pp);
Simon Huntd3ceffa2015-08-25 12:44:35 -0700591 sendMessage(envelope(SHOW_SUMMARY, sid, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700592 }
593
Simon Huntd2747a02015-04-30 22:41:16 -0700594
Thomas Vachuska329af532015-03-10 02:08:33 -0700595 private void cancelAllRequests() {
596 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700597 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700598 }
599
600 // Sends all controller nodes to the client as node-added messages.
601 private void sendAllInstances(String messageType) {
602 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
603 Collections.sort(nodes, NODE_COMPARATOR);
604 for (ControllerNode node : nodes) {
605 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
606 messageType));
607 }
608 }
609
610 // Sends all devices to the client as device-added messages.
611 private void sendAllDevices() {
612 // Send optical first, others later for layered rendering
613 for (Device device : deviceService.getDevices()) {
614 if (device.type() == Device.Type.ROADM) {
615 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
616 }
617 }
618 for (Device device : deviceService.getDevices()) {
619 if (device.type() != Device.Type.ROADM) {
620 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
621 }
622 }
623 }
624
625 // Sends all links to the client as link-added messages.
626 private void sendAllLinks() {
627 // Send optical first, others later for layered rendering
628 for (Link link : linkService.getLinks()) {
629 if (link.type() == Link.Type.OPTICAL) {
630 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
631 }
632 }
633 for (Link link : linkService.getLinks()) {
634 if (link.type() != Link.Type.OPTICAL) {
635 sendMessage(linkMessage(new LinkEvent(LINK_ADDED, link)));
636 }
637 }
638 }
639
640 // Sends all hosts to the client as host-added messages.
641 private void sendAllHosts() {
642 for (Host host : hostService.getHosts()) {
643 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
644 }
645 }
646
Thomas Vachuska329af532015-03-10 02:08:33 -0700647 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
648 Set<ConnectPoint> points = new HashSet<>();
649 for (HostId hostId : hostIds) {
650 points.add(getHostLocation(hostId));
651 }
652 return points;
653 }
654
655 private HostLocation getHostLocation(HostId hostId) {
656 return hostService.getHost(hostId).location();
657 }
658
659 // Produces a list of host ids from the specified JSON array.
660 private Set<HostId> getHostIds(ArrayNode ids) {
661 Set<HostId> hostIds = new HashSet<>();
662 for (JsonNode id : ids) {
663 hostIds.add(hostId(id.asText()));
664 }
665 return hostIds;
666 }
667
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700668 private void sendTopoStartDone() {
669 sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode()));
670 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700671
Simon Huntd2747a02015-04-30 22:41:16 -0700672 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700673 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700674 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700675 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700676 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700677 }
678
679 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700680 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700681 summaryTask.cancel();
682 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700683 }
Simon Huntd2747a02015-04-30 22:41:16 -0700684 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700685 }
686
Thomas Vachuska329af532015-03-10 02:08:33 -0700687
688 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700689 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700690 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700691 clusterService.addListener(clusterListener);
692 mastershipService.addListener(mastershipListener);
693 deviceService.addListener(deviceListener);
694 linkService.addListener(linkListener);
695 hostService.addListener(hostListener);
696 intentService.addListener(intentListener);
697 flowService.addListener(flowListener);
698 }
699
700 // Removes all internal listeners.
701 private synchronized void removeListeners() {
702 if (!listenersRemoved) {
703 listenersRemoved = true;
704 clusterService.removeListener(clusterListener);
705 mastershipService.removeListener(mastershipListener);
706 deviceService.removeListener(deviceListener);
707 linkService.removeListener(linkListener);
708 hostService.removeListener(hostListener);
709 intentService.removeListener(intentListener);
710 flowService.removeListener(flowListener);
711 }
712 }
713
714 // Cluster event listener.
715 private class InternalClusterListener implements ClusterEventListener {
716 @Override
717 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700718 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700719 }
720 }
721
722 // Mastership change listener
723 private class InternalMastershipListener implements MastershipListener {
724 @Override
725 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700726 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700727 sendAllInstances(UPDATE_INSTANCE);
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700728 Device device = deviceService.getDevice(event.subject());
729 if (device != null) {
730 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
731 }
732 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700733 }
734 }
735
736 // Device event listener.
737 private class InternalDeviceListener implements DeviceListener {
738 @Override
739 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700740 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700741 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700742 eventAccummulator.add(event);
743 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700744 }
745 }
746
747 // Link event listener.
748 private class InternalLinkListener implements LinkListener {
749 @Override
750 public void event(LinkEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700751 msgSender.execute(() -> sendMessage(linkMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700752 eventAccummulator.add(event);
753 }
754 }
755
756 // Host event listener.
757 private class InternalHostListener implements HostListener {
758 @Override
759 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700760 msgSender.execute(() -> sendMessage(hostMessage(event)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700761 eventAccummulator.add(event);
762 }
763 }
764
765 // Intent event listener.
766 private class InternalIntentListener implements IntentListener {
767 @Override
768 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700769 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700770 eventAccummulator.add(event);
771 }
772 }
773
774 // Intent event listener.
775 private class InternalFlowListener implements FlowRuleListener {
776 @Override
777 public void event(FlowRuleEvent event) {
778 eventAccummulator.add(event);
779 }
780 }
781
Simon Huntd2747a02015-04-30 22:41:16 -0700782
Simon Hunta17fa672015-08-19 18:42:22 -0700783 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700784
785 // Periodic update of the summary information
786 private class SummaryMonitor extends TimerTask {
787 @Override
788 public void run() {
789 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700790 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700791 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700792 }
793 } catch (Exception e) {
794 log.warn("Unable to handle summary request due to {}", e.getMessage());
795 log.warn("Boom!", e);
796 }
797 }
798 }
799
800 // Accumulates events to drive methodic update of the summary pane.
801 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
802 protected InternalEventAccummulator() {
803 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
804 }
805
806 @Override
807 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -0700808 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700809 long now = System.currentTimeMillis();
810 String me = this.toString();
811 String miniMe = me.replaceAll("^.*@", "me@");
812 log.debug("Time: {}; this: {}, processing items ({} events)",
813 now, miniMe, items.size());
814 // End-of-Debugging
815
Thomas Vachuska329af532015-03-10 02:08:33 -0700816 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700817 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700818 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700819 }
820 } catch (Exception e) {
821 log.warn("Unable to handle summary request due to {}", e.getMessage());
822 log.debug("Boom!", e);
823 }
824 }
825 }
826}