blob: fdfdd1bf0f6c464168c4074859d993c1c53bfd73 [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;
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;
Simon Hunt5c1a9382016-06-01 19:35:35 -070074import java.util.Map;
Thomas Vachuska329af532015-03-10 02:08:33 -070075import java.util.Set;
76import java.util.Timer;
77import java.util.TimerTask;
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070078import java.util.concurrent.ExecutorService;
Thomas Vachuska329af532015-03-10 02:08:33 -070079
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070080import static java.util.concurrent.Executors.newSingleThreadExecutor;
81import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska329af532015-03-10 02:08:33 -070082import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
83import static org.onosproject.net.DeviceId.deviceId;
84import static org.onosproject.net.HostId.hostId;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070085import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
86import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
87import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
Thomas Vachuska329af532015-03-10 02:08:33 -070088import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
89import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntd3ceffa2015-08-25 12:44:35 -070090import static org.onosproject.ui.JsonUtils.envelope;
Viswanath KSP0f297702016-08-13 18:02:43 +053091import static org.onosproject.ui.JsonUtils.string;
Simon Hunt52560662015-08-27 22:46:44 -070092import static org.onosproject.ui.topo.TopoJson.highlightsMessage;
93import static org.onosproject.ui.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070094
95/**
96 * Web socket capable of interacting with the GUI topology view.
97 */
98public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
99
Simon Huntb745ca62015-07-28 15:37:11 -0700100 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -0700101 private static final String REQ_DETAILS = "requestDetails";
102 private static final String UPDATE_META = "updateMeta";
103 private static final String ADD_HOST_INTENT = "addHostIntent";
Viswanath KSP0f297702016-08-13 18:02:43 +0530104 private static final String REMOVE_INTENT = "removeIntent";
Simon Huntd2747a02015-04-30 22:41:16 -0700105 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
106 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
107 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
108 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
109 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700110 private static final String SEL_INTENT = "selectIntent";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700111 private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
112 private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700113 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
114 private static final String CANCEL_TRAFFIC = "cancelTraffic";
115 private static final String REQ_SUMMARY = "requestSummary";
116 private static final String CANCEL_SUMMARY = "cancelSummary";
117 private static final String EQ_MASTERS = "equalizeMasters";
118 private static final String SPRITE_LIST_REQ = "spriteListRequest";
119 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
120 private static final String TOPO_START = "topoStart";
Simon Hunt732bb2e2015-05-13 18:32:16 -0700121 private static final String TOPO_HEARTBEAT = "topoHeartbeat";
Simon Hunte05cae42015-07-23 17:35:24 -0700122 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700123 private static final String TOPO_STOP = "topoStop";
124
Simon Huntb745ca62015-07-28 15:37:11 -0700125 // outgoing event types
126 private static final String SHOW_SUMMARY = "showSummary";
127 private static final String SHOW_DETAILS = "showDetails";
128 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
129 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
130 private static final String UPDATE_INSTANCE = "updateInstance";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700131 private static final String TOPO_START_DONE = "topoStartDone";
Simon Huntb745ca62015-07-28 15:37:11 -0700132
133 // fields
Simon Hunt5c1a9382016-06-01 19:35:35 -0700134 private static final String PAYLOAD = "payload";
135 private static final String EXTRA = "extra";
Simon Huntb745ca62015-07-28 15:37:11 -0700136 private static final String ID = "id";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700137 private static final String KEY = "key";
138 private static final String APP_ID = "appId";
139 private static final String APP_NAME = "appName";
Simon Huntb745ca62015-07-28 15:37:11 -0700140 private static final String DEVICE = "device";
141 private static final String HOST = "host";
142 private static final String CLASS = "class";
143 private static final String UNKNOWN = "unknown";
144 private static final String ONE = "one";
145 private static final String TWO = "two";
146 private static final String SRC = "src";
147 private static final String DST = "dst";
148 private static final String DATA = "data";
149 private static final String NAME = "name";
150 private static final String NAMES = "names";
151 private static final String ACTIVATE = "activate";
152 private static final String DEACTIVATE = "deactivate";
Viswanath KSP813a20d2016-09-13 04:25:41 +0530153 private static final String PURGE = "purge";
Simon Huntb745ca62015-07-28 15:37:11 -0700154
Simon Huntd2747a02015-04-30 22:41:16 -0700155
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700156 private static final String MY_APP_ID = "org.onosproject.gui";
Thomas Vachuska329af532015-03-10 02:08:33 -0700157
Simon Hunta17fa672015-08-19 18:42:22 -0700158 private static final long TRAFFIC_PERIOD = 5000;
159 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700160
161 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Thomas Vachuskac0fe09a2015-05-21 12:56:22 -0700162 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700163
164
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700165 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700166
167 private static final int MAX_EVENTS = 1000;
168 private static final int MAX_BATCH_MS = 5000;
169 private static final int MAX_IDLE_MS = 1000;
170
171 private ApplicationId appId;
172
173 private final ClusterEventListener clusterListener = new InternalClusterListener();
174 private final MastershipListener mastershipListener = new InternalMastershipListener();
175 private final DeviceListener deviceListener = new InternalDeviceListener();
176 private final LinkListener linkListener = new InternalLinkListener();
177 private final HostListener hostListener = new InternalHostListener();
178 private final IntentListener intentListener = new InternalIntentListener();
179 private final FlowRuleListener flowListener = new InternalFlowListener();
180
181 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700182 private final ExecutorService msgSender =
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700183 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender", log));
Thomas Vachuska329af532015-03-10 02:08:33 -0700184
Simon Hunta17fa672015-08-19 18:42:22 -0700185 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700186 private TrafficMonitor traffic;
Thomas Vachuska329af532015-03-10 02:08:33 -0700187
Simon Huntd2747a02015-04-30 22:41:16 -0700188 private TimerTask summaryTask = null;
189 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700190
Simon Huntd5b96732016-07-08 13:22:27 -0700191 private volatile boolean listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700192
Thomas Vachuska329af532015-03-10 02:08:33 -0700193
194 @Override
195 public void init(UiConnection connection, ServiceDirectory directory) {
196 super.init(connection, directory);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700197 appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
Simon Hunt4fc86852015-08-20 17:57:52 -0700198 traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700199 }
200
201 @Override
202 public void destroy() {
203 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700204 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700205 super.destroy();
206 }
207
Thomas Vachuska329af532015-03-10 02:08:33 -0700208 @Override
Simon Huntda580882015-05-12 20:58:18 -0700209 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700210 return ImmutableSet.of(
211 new TopoStart(),
Simon Hunt732bb2e2015-05-13 18:32:16 -0700212 new TopoHeartbeat(),
Simon Hunte05cae42015-07-23 17:35:24 -0700213 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700214 new TopoStop(),
215 new ReqSummary(),
216 new CancelSummary(),
217 new SpriteListReq(),
218 new SpriteDataReq(),
219 new RequestDetails(),
220 new UpdateMeta(),
221 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700222
Simon Huntd2747a02015-04-30 22:41:16 -0700223 // TODO: migrate traffic related to separate app
224 new AddHostIntent(),
225 new AddMultiSourceIntent(),
Viswanath KSP0f297702016-08-13 18:02:43 +0530226 new RemoveIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700227
228 new ReqAllFlowTraffic(),
229 new ReqAllPortTraffic(),
230 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700231 new ReqRelatedIntents(),
232 new ReqNextIntent(),
233 new ReqPrevIntent(),
234 new ReqSelectedIntentTraffic(),
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700235 new SelIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700236
Simon Huntd2747a02015-04-30 22:41:16 -0700237 new CancelTraffic()
238 );
239 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700240
Simon Hunte05cae42015-07-23 17:35:24 -0700241 /**
242 * Injects the topology overlay cache.
243 *
244 * @param overlayCache injected cache
245 */
246 void setOverlayCache(TopoOverlayCache overlayCache) {
247 this.overlayCache = overlayCache;
248 }
249
Simon Huntd2747a02015-04-30 22:41:16 -0700250 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700251
Simon Huntd2747a02015-04-30 22:41:16 -0700252 private final class TopoStart extends RequestHandler {
253 private TopoStart() {
254 super(TOPO_START);
255 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700256
Simon Huntd2747a02015-04-30 22:41:16 -0700257 @Override
258 public void process(long sid, ObjectNode payload) {
259 addListeners();
260 sendAllInstances(null);
261 sendAllDevices();
262 sendAllLinks();
263 sendAllHosts();
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700264 sendTopoStartDone();
Thomas Vachuska329af532015-03-10 02:08:33 -0700265 }
266 }
267
Simon Hunt732bb2e2015-05-13 18:32:16 -0700268 private final class TopoHeartbeat extends RequestHandler {
269 private TopoHeartbeat() {
270 super(TOPO_HEARTBEAT);
271 }
272
273 @Override
274 public void process(long sid, ObjectNode payload) {
275 // place holder for now
276 }
277 }
278
Simon Hunte05cae42015-07-23 17:35:24 -0700279 private final class TopoSelectOverlay extends RequestHandler {
280 private TopoSelectOverlay() {
281 super(TOPO_SELECT_OVERLAY);
282 }
283
284 @Override
285 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700286 String deact = string(payload, DEACTIVATE);
287 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700288 overlayCache.switchOverlay(deact, act);
289 }
290 }
291
Simon Huntd2747a02015-04-30 22:41:16 -0700292 private final class TopoStop extends RequestHandler {
293 private TopoStop() {
294 super(TOPO_STOP);
295 }
296
297 @Override
298 public void process(long sid, ObjectNode payload) {
Simon Hunt1ad59272015-11-10 15:23:21 -0800299 removeListeners();
Simon Huntd2747a02015-04-30 22:41:16 -0700300 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700301 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700302 }
303 }
304
305 private final class ReqSummary extends RequestHandler {
306 private ReqSummary() {
307 super(REQ_SUMMARY);
308 }
309
310 @Override
311 public void process(long sid, ObjectNode payload) {
312 requestSummary(sid);
313 startSummaryMonitoring();
314 }
315 }
316
317 private final class CancelSummary extends RequestHandler {
318 private CancelSummary() {
319 super(CANCEL_SUMMARY);
320 }
321
322 @Override
323 public void process(long sid, ObjectNode payload) {
324 stopSummaryMonitoring();
325 }
326 }
327
328 private final class SpriteListReq extends RequestHandler {
329 private SpriteListReq() {
330 super(SPRITE_LIST_REQ);
331 }
332
333 @Override
334 public void process(long sid, ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700335 ObjectNode root = objectNode();
336 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700337 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700338 root.set(NAMES, names);
339 sendMessage(SPRITE_LIST_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700340 }
341 }
342
343 private final class SpriteDataReq extends RequestHandler {
344 private SpriteDataReq() {
345 super(SPRITE_DATA_REQ);
346 }
347
348 @Override
349 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700350 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700351 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700352 root.set(DATA, get(SpriteService.class).get(name));
353 sendMessage(SPRITE_DATA_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700354 }
355 }
356
357 private final class RequestDetails extends RequestHandler {
358 private RequestDetails() {
359 super(REQ_DETAILS);
360 }
361
362 @Override
363 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700364 String type = string(payload, CLASS, UNKNOWN);
365 String id = string(payload, ID);
366 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700367
Simon Huntb745ca62015-07-28 15:37:11 -0700368 if (type.equals(DEVICE)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700369 DeviceId did = deviceId(id);
370 pp = deviceDetails(did, sid);
371 overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
Simon Huntb745ca62015-07-28 15:37:11 -0700372 } else if (type.equals(HOST)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700373 HostId hid = hostId(id);
374 pp = hostDetails(hid, sid);
375 overlayCache.currentOverlay().modifyHostDetails(pp, hid);
Simon Huntd2747a02015-04-30 22:41:16 -0700376 }
Simon Huntb745ca62015-07-28 15:37:11 -0700377
Simon Huntd3ceffa2015-08-25 12:44:35 -0700378 sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
Simon Huntd2747a02015-04-30 22:41:16 -0700379 }
380 }
381
382 private final class UpdateMeta extends RequestHandler {
383 private UpdateMeta() {
384 super(UPDATE_META);
385 }
386
387 @Override
388 public void process(long sid, ObjectNode payload) {
389 updateMetaUi(payload);
390 }
391 }
392
393 private final class EqMasters extends RequestHandler {
394 private EqMasters() {
395 super(EQ_MASTERS);
396 }
397
398 @Override
399 public void process(long sid, ObjectNode payload) {
400 directory.get(MastershipAdminService.class).balanceRoles();
401 }
402 }
403
Simon Hunta17fa672015-08-19 18:42:22 -0700404
405 // ========= -----------------------------------------------------------------
406
Simon Huntd2747a02015-04-30 22:41:16 -0700407 // === TODO: move traffic related classes to traffic app
408
409 private final class AddHostIntent extends RequestHandler {
410 private AddHostIntent() {
411 super(ADD_HOST_INTENT);
412 }
413
414 @Override
415 public void process(long sid, ObjectNode payload) {
416 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700417 HostId one = hostId(string(payload, ONE));
418 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700419
420 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700421 .appId(appId)
422 .one(one)
423 .two(two)
424 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700425
426 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700427 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
428 traffic.monitor(intent);
429 }
Simon Huntd2747a02015-04-30 22:41:16 -0700430 }
431 }
432
Viswanath KSP0f297702016-08-13 18:02:43 +0530433 private Intent findIntentByPayload(ObjectNode payload) {
434 int appId = Integer.parseInt(string(payload, APP_ID));
435 String appName = string(payload, APP_NAME);
436 ApplicationId applicId = new DefaultApplicationId(appId, appName);
437 long intentKey = Long.decode(string(payload, KEY));
438
439 Key key = Key.of(intentKey, applicId);
440 log.debug("Attempting to select intent by key={}", key);
441
Viswanath KSP813a20d2016-09-13 04:25:41 +0530442 return intentService.getIntent(key);
Viswanath KSP0f297702016-08-13 18:02:43 +0530443 }
444
445 private final class RemoveIntent extends RequestHandler {
446 private RemoveIntent() {
447 super(REMOVE_INTENT);
448 }
449
Viswanath KSP813a20d2016-09-13 04:25:41 +0530450 private boolean isIntentToBePurged(ObjectNode payload) {
451 return bool(payload, PURGE);
452 }
453
Viswanath KSP0f297702016-08-13 18:02:43 +0530454 @Override
455 public void process(long sid, ObjectNode payload) {
456 Intent intent = findIntentByPayload(payload);
457 if (intent == null) {
458 log.warn("Unable to find intent from payload {}", payload);
459 } else {
Viswanath KSP813a20d2016-09-13 04:25:41 +0530460 log.debug("Withdrawing / Purging intent {}", intent.key());
461 if (isIntentToBePurged(payload)) {
462 intentService.purge(intent);
463 } else {
464 intentService.withdraw(intent);
465 }
Viswanath KSP0f297702016-08-13 18:02:43 +0530466 }
467 }
468 }
469
Simon Huntd2747a02015-04-30 22:41:16 -0700470 private final class AddMultiSourceIntent extends RequestHandler {
471 private AddMultiSourceIntent() {
472 super(ADD_MULTI_SRC_INTENT);
473 }
474
475 @Override
476 public void process(long sid, ObjectNode payload) {
477 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700478 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
479 HostId dst = hostId(string(payload, DST));
Simon Huntd2747a02015-04-30 22:41:16 -0700480 Host dstHost = hostService.getHost(dst);
481
482 Set<ConnectPoint> ingressPoints = getHostLocations(src);
483
484 // FIXME: clearly, this is not enough
485 TrafficSelector selector = DefaultTrafficSelector.builder()
486 .matchEthDst(dstHost.mac()).build();
487 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
488
489 MultiPointToSinglePointIntent intent =
490 MultiPointToSinglePointIntent.builder()
491 .appId(appId)
492 .selector(selector)
493 .treatment(treatment)
494 .ingressPoints(ingressPoints)
495 .egressPoint(dstHost.location())
496 .build();
497
498 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700499 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
500 traffic.monitor(intent);
501 }
Simon Huntd2747a02015-04-30 22:41:16 -0700502 }
503 }
504
Simon Hunta17fa672015-08-19 18:42:22 -0700505 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700506
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700507 private final class ReqAllFlowTraffic extends RequestHandler {
508 private ReqAllFlowTraffic() {
509 super(REQ_ALL_FLOW_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700510 }
511
512 @Override
513 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700514 traffic.monitor(Mode.ALL_FLOW_TRAFFIC);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700515 }
516 }
517
518 private final class ReqAllPortTraffic extends RequestHandler {
519 private ReqAllPortTraffic() {
520 super(REQ_ALL_PORT_TRAFFIC);
521 }
522
523 @Override
524 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700525 traffic.monitor(Mode.ALL_PORT_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700526 }
527 }
528
529 private final class ReqDevLinkFlows extends RequestHandler {
530 private ReqDevLinkFlows() {
531 super(REQ_DEV_LINK_FLOWS);
532 }
533
534 @Override
535 public void process(long sid, ObjectNode payload) {
Simon Hunta17fa672015-08-19 18:42:22 -0700536 NodeSelection nodeSelection =
537 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700538 traffic.monitor(Mode.DEV_LINK_FLOWS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700539 }
540 }
541
542 private final class ReqRelatedIntents extends RequestHandler {
543 private ReqRelatedIntents() {
544 super(REQ_RELATED_INTENTS);
545 }
546
547 @Override
548 public void process(long sid, ObjectNode payload) {
549 NodeSelection nodeSelection =
550 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700551 traffic.monitor(Mode.RELATED_INTENTS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700552 }
553 }
554
555 private final class ReqNextIntent extends RequestHandler {
556 private ReqNextIntent() {
557 super(REQ_NEXT_INTENT);
558 }
559
560 @Override
561 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700562 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700563 }
564 }
565
566 private final class ReqPrevIntent extends RequestHandler {
567 private ReqPrevIntent() {
568 super(REQ_PREV_INTENT);
569 }
570
571 @Override
572 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700573 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700574 }
575 }
576
577 private final class ReqSelectedIntentTraffic extends RequestHandler {
578 private ReqSelectedIntentTraffic() {
579 super(REQ_SEL_INTENT_TRAFFIC);
580 }
581
582 @Override
583 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700584 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700585 }
586 }
587
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700588 private final class SelIntent extends RequestHandler {
589 private SelIntent() {
590 super(SEL_INTENT);
591 }
592
593 @Override
594 public void process(long sid, ObjectNode payload) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530595 Intent intent = findIntentByPayload(payload);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700596 if (intent == null) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530597 log.warn("Unable to find intent from payload {}", payload);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700598 } else {
Viswanath KSP0f297702016-08-13 18:02:43 +0530599 log.debug("starting to monitor intent {}", intent.key());
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700600 traffic.monitor(intent);
601 }
602 }
603 }
604
Simon Huntd2747a02015-04-30 22:41:16 -0700605 private final class CancelTraffic extends RequestHandler {
606 private CancelTraffic() {
607 super(CANCEL_TRAFFIC);
608 }
609
610 @Override
611 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700612 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700613 }
614 }
615
616 //=======================================================================
617
Simon Hunta17fa672015-08-19 18:42:22 -0700618 // Converts highlights to JSON format and sends the message to the client
619 protected void sendHighlights(Highlights highlights) {
Simon Hunt52560662015-08-27 22:46:44 -0700620 sendMessage(highlightsMessage(highlights));
Thomas Vachuska329af532015-03-10 02:08:33 -0700621 }
622
Simon Huntd2747a02015-04-30 22:41:16 -0700623 // Subscribes for summary messages.
624 private synchronized void requestSummary(long sid) {
Simon Hunt0af1ec32015-07-24 12:17:55 -0700625 PropertyPanel pp = summmaryMessage(sid);
626 overlayCache.currentOverlay().modifySummary(pp);
Simon Huntd3ceffa2015-08-25 12:44:35 -0700627 sendMessage(envelope(SHOW_SUMMARY, sid, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700628 }
629
Simon Huntd2747a02015-04-30 22:41:16 -0700630
Thomas Vachuska329af532015-03-10 02:08:33 -0700631 private void cancelAllRequests() {
632 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700633 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700634 }
635
636 // Sends all controller nodes to the client as node-added messages.
637 private void sendAllInstances(String messageType) {
638 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
639 Collections.sort(nodes, NODE_COMPARATOR);
640 for (ControllerNode node : nodes) {
641 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
Simon Hunt5c1a9382016-06-01 19:35:35 -0700642 messageType));
Thomas Vachuska329af532015-03-10 02:08:33 -0700643 }
644 }
645
646 // Sends all devices to the client as device-added messages.
647 private void sendAllDevices() {
648 // Send optical first, others later for layered rendering
649 for (Device device : deviceService.getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200650 if ((device.type() == Device.Type.ROADM) ||
Simon Hunt5c1a9382016-06-01 19:35:35 -0700651 (device.type() == Device.Type.OTN)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700652 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
653 }
654 }
655 for (Device device : deviceService.getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200656 if ((device.type() != Device.Type.ROADM) &&
Simon Hunt5c1a9382016-06-01 19:35:35 -0700657 (device.type() != Device.Type.OTN)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700658 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
659 }
660 }
661 }
662
663 // Sends all links to the client as link-added messages.
664 private void sendAllLinks() {
665 // Send optical first, others later for layered rendering
666 for (Link link : linkService.getLinks()) {
667 if (link.type() == Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700668 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700669 }
670 }
671 for (Link link : linkService.getLinks()) {
672 if (link.type() != Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700673 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700674 }
675 }
676 }
677
Simon Hunt5c1a9382016-06-01 19:35:35 -0700678 // Temporary mechanism to support topology overlays adding their own
679 // properties to the link events.
680 private ObjectNode composeLinkMessage(LinkEvent event) {
681 // start with base message
682 ObjectNode msg = linkMessage(event);
683 Map<String, String> additional =
684 overlayCache.currentOverlay().additionalLinkData(event);
685
686 if (additional != null) {
687 // attach additional key-value pairs as extra data structure
688 ObjectNode payload = (ObjectNode) msg.get(PAYLOAD);
689 payload.set(EXTRA, createExtra(additional));
690 }
691 return msg;
692 }
693
694 private ObjectNode createExtra(Map<String, String> additional) {
695 ObjectNode extra = objectNode();
696 for (Map.Entry<String, String> entry : additional.entrySet()) {
697 extra.put(entry.getKey(), entry.getValue());
698 }
699 return extra;
700 }
701
Thomas Vachuska329af532015-03-10 02:08:33 -0700702 // Sends all hosts to the client as host-added messages.
703 private void sendAllHosts() {
704 for (Host host : hostService.getHosts()) {
705 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
706 }
707 }
708
Thomas Vachuska329af532015-03-10 02:08:33 -0700709 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
710 Set<ConnectPoint> points = new HashSet<>();
711 for (HostId hostId : hostIds) {
712 points.add(getHostLocation(hostId));
713 }
714 return points;
715 }
716
717 private HostLocation getHostLocation(HostId hostId) {
718 return hostService.getHost(hostId).location();
719 }
720
721 // Produces a list of host ids from the specified JSON array.
722 private Set<HostId> getHostIds(ArrayNode ids) {
723 Set<HostId> hostIds = new HashSet<>();
724 for (JsonNode id : ids) {
725 hostIds.add(hostId(id.asText()));
726 }
727 return hostIds;
728 }
729
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700730 private void sendTopoStartDone() {
731 sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode()));
732 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700733
Simon Huntd2747a02015-04-30 22:41:16 -0700734 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700735 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700736 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700737 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700738 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700739 }
740
741 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700742 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700743 summaryTask.cancel();
744 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700745 }
Simon Huntd2747a02015-04-30 22:41:16 -0700746 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700747 }
748
Thomas Vachuska329af532015-03-10 02:08:33 -0700749
750 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700751 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700752 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700753 clusterService.addListener(clusterListener);
754 mastershipService.addListener(mastershipListener);
755 deviceService.addListener(deviceListener);
756 linkService.addListener(linkListener);
757 hostService.addListener(hostListener);
758 intentService.addListener(intentListener);
759 flowService.addListener(flowListener);
760 }
761
762 // Removes all internal listeners.
763 private synchronized void removeListeners() {
764 if (!listenersRemoved) {
765 listenersRemoved = true;
766 clusterService.removeListener(clusterListener);
767 mastershipService.removeListener(mastershipListener);
768 deviceService.removeListener(deviceListener);
769 linkService.removeListener(linkListener);
770 hostService.removeListener(hostListener);
771 intentService.removeListener(intentListener);
772 flowService.removeListener(flowListener);
773 }
774 }
775
776 // Cluster event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700777 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
778 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700779 private class InternalClusterListener implements ClusterEventListener {
780 @Override
781 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700782 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700783 }
784 }
785
786 // Mastership change listener
Simon Hunt7092cc42016-04-06 18:40:17 -0700787 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
788 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700789 private class InternalMastershipListener implements MastershipListener {
790 @Override
791 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700792 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700793 sendAllInstances(UPDATE_INSTANCE);
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700794 Device device = deviceService.getDevice(event.subject());
795 if (device != null) {
796 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
797 }
798 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700799 }
800 }
801
802 // Device event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700803 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
804 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700805 private class InternalDeviceListener implements DeviceListener {
806 @Override
807 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700808 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700809 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800810 msgSender.execute(traffic::pokeIntent);
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700811 eventAccummulator.add(event);
812 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700813 }
814 }
815
816 // Link event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700817 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
818 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700819 private class InternalLinkListener implements LinkListener {
820 @Override
821 public void event(LinkEvent event) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700822 msgSender.execute(() -> sendMessage(composeLinkMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800823 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700824 eventAccummulator.add(event);
825 }
826 }
827
828 // Host event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700829 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
830 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700831 private class InternalHostListener implements HostListener {
832 @Override
833 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700834 msgSender.execute(() -> sendMessage(hostMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800835 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700836 eventAccummulator.add(event);
837 }
838 }
839
840 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700841 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
842 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700843 private class InternalIntentListener implements IntentListener {
844 @Override
845 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700846 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700847 eventAccummulator.add(event);
848 }
849 }
850
851 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700852 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
853 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700854 private class InternalFlowListener implements FlowRuleListener {
855 @Override
856 public void event(FlowRuleEvent event) {
857 eventAccummulator.add(event);
858 }
859 }
860
Simon Huntd2747a02015-04-30 22:41:16 -0700861
Simon Hunta17fa672015-08-19 18:42:22 -0700862 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700863
864 // Periodic update of the summary information
865 private class SummaryMonitor extends TimerTask {
866 @Override
867 public void run() {
868 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700869 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700870 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700871 }
872 } catch (Exception e) {
873 log.warn("Unable to handle summary request due to {}", e.getMessage());
874 log.warn("Boom!", e);
875 }
876 }
877 }
878
879 // Accumulates events to drive methodic update of the summary pane.
880 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
881 protected InternalEventAccummulator() {
882 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
883 }
884
885 @Override
886 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -0700887 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700888 long now = System.currentTimeMillis();
889 String me = this.toString();
890 String miniMe = me.replaceAll("^.*@", "me@");
891 log.debug("Time: {}; this: {}, processing items ({} events)",
Simon Hunt5c1a9382016-06-01 19:35:35 -0700892 now, miniMe, items.size());
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700893 // End-of-Debugging
894
Thomas Vachuska329af532015-03-10 02:08:33 -0700895 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700896 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700897 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700898 }
899 } catch (Exception e) {
900 log.warn("Unable to handle summary request due to {}", e.getMessage());
901 log.debug("Boom!", e);
902 }
903 }
904 }
905}