blob: a359964ae070428348b8488f16936b0f1ecb06a9 [file] [log] [blame]
Thomas Vachuska329af532015-03-10 02:08:33 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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;
Thomas Vachuska329af532015-03-10 02:08:33 -070032import org.onosproject.mastership.MastershipEvent;
33import org.onosproject.mastership.MastershipListener;
34import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.Device;
Simon Huntde99e0b2015-10-23 18:54:06 -070036import org.onosproject.net.DeviceId;
Thomas Vachuska329af532015-03-10 02:08:33 -070037import org.onosproject.net.Host;
38import org.onosproject.net.HostId;
39import org.onosproject.net.HostLocation;
40import org.onosproject.net.Link;
41import org.onosproject.net.device.DeviceEvent;
42import org.onosproject.net.device.DeviceListener;
43import org.onosproject.net.flow.DefaultTrafficSelector;
44import org.onosproject.net.flow.DefaultTrafficTreatment;
45import org.onosproject.net.flow.FlowRuleEvent;
46import org.onosproject.net.flow.FlowRuleListener;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.host.HostEvent;
50import org.onosproject.net.host.HostListener;
51import org.onosproject.net.intent.HostToHostIntent;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070052import org.onosproject.net.intent.Intent;
Thomas Vachuska329af532015-03-10 02:08:33 -070053import org.onosproject.net.intent.IntentEvent;
54import org.onosproject.net.intent.IntentListener;
Deepa Vaddireddy63340922017-01-19 08:15:31 +053055import org.onosproject.net.intent.IntentService;
Andrea Campanella732ea832017-02-06 09:25:59 -080056import org.onosproject.net.intent.IntentState;
Simon Hunt21281fd2017-03-30 22:28:28 -070057import org.onosproject.net.intent.Key;
58import org.onosproject.net.intent.MultiPointToSinglePointIntent;
Thomas Vachuska329af532015-03-10 02:08:33 -070059import org.onosproject.net.link.LinkEvent;
60import org.onosproject.net.link.LinkListener;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070061import org.onosproject.ui.JsonUtils;
Simon Huntd2747a02015-04-30 22:41:16 -070062import org.onosproject.ui.RequestHandler;
Thomas Vachuska329af532015-03-10 02:08:33 -070063import org.onosproject.ui.UiConnection;
Simon Hunt1911fe42017-05-02 18:25:58 -070064import org.onosproject.ui.impl.TrafficMonitorBase.Mode;
Simon Hunta17fa672015-08-19 18:42:22 -070065import org.onosproject.ui.topo.Highlights;
Simon Huntd3ceffa2015-08-25 12:44:35 -070066import org.onosproject.ui.topo.NodeSelection;
Simon Hunt0af1ec32015-07-24 12:17:55 -070067import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070068
69import java.util.ArrayList;
Simon Huntd2747a02015-04-30 22:41:16 -070070import java.util.Collection;
Thomas Vachuska329af532015-03-10 02:08:33 -070071import 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;
Simon Hunta58d8942017-08-11 12:51:14 -070083import static org.onosproject.net.ConnectPoint.deviceConnectPoint;
Thomas Vachuska329af532015-03-10 02:08:33 -070084import static org.onosproject.net.DeviceId.deviceId;
85import static org.onosproject.net.HostId.hostId;
Simon Hunt879ce452017-08-10 23:32:00 -070086import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
87import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
88import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
Thomas Vachuska329af532015-03-10 02:08:33 -070089import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
90import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntd3ceffa2015-08-25 12:44:35 -070091import static org.onosproject.ui.JsonUtils.envelope;
Viswanath KSP0f297702016-08-13 18:02:43 +053092import static org.onosproject.ui.JsonUtils.string;
Simon Hunt52560662015-08-27 22:46:44 -070093import static org.onosproject.ui.topo.TopoJson.highlightsMessage;
94import static org.onosproject.ui.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070095
96/**
97 * Web socket capable of interacting with the GUI topology view.
98 */
99public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
100
Simon Huntb745ca62015-07-28 15:37:11 -0700101 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -0700102 private static final String REQ_DETAILS = "requestDetails";
103 private static final String UPDATE_META = "updateMeta";
104 private static final String ADD_HOST_INTENT = "addHostIntent";
Viswanath KSP0f297702016-08-13 18:02:43 +0530105 private static final String REMOVE_INTENT = "removeIntent";
Deepa Vaddireddy63340922017-01-19 08:15:31 +0530106 private static final String REMOVE_INTENTS = "removeIntents";
Viswanath KSP14aee092016-10-02 01:47:40 +0530107 private static final String RESUBMIT_INTENT = "resubmitIntent";
Simon Huntd2747a02015-04-30 22:41:16 -0700108 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
109 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
110 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
111 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
112 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700113 private static final String SEL_INTENT = "selectIntent";
Simon Hunt21281fd2017-03-30 22:28:28 -0700114 private static final String REQ_ALL_TRAFFIC = "requestAllTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700115 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
116 private static final String CANCEL_TRAFFIC = "cancelTraffic";
117 private static final String REQ_SUMMARY = "requestSummary";
118 private static final String CANCEL_SUMMARY = "cancelSummary";
119 private static final String EQ_MASTERS = "equalizeMasters";
120 private static final String SPRITE_LIST_REQ = "spriteListRequest";
121 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
122 private static final String TOPO_START = "topoStart";
Simon Hunte05cae42015-07-23 17:35:24 -0700123 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700124 private static final String TOPO_STOP = "topoStop";
Andrea Campanella732ea832017-02-06 09:25:59 -0800125 private static final String SEL_PROTECTED_INTENT = "selectProtectedIntent";
126 private static final String CANCEL_PROTECTED_INTENT_HIGHLIGHT = "cancelProtectedIntentHighlight";
127
Simon Huntb745ca62015-07-28 15:37:11 -0700128 // outgoing event types
129 private static final String SHOW_SUMMARY = "showSummary";
130 private static final String SHOW_DETAILS = "showDetails";
131 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
132 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
133 private static final String UPDATE_INSTANCE = "updateInstance";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700134 private static final String TOPO_START_DONE = "topoStartDone";
Simon Huntb745ca62015-07-28 15:37:11 -0700135
136 // fields
Simon Hunt5c1a9382016-06-01 19:35:35 -0700137 private static final String PAYLOAD = "payload";
138 private static final String EXTRA = "extra";
Simon Huntb745ca62015-07-28 15:37:11 -0700139 private static final String ID = "id";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700140 private static final String KEY = "key";
Simon Hunta58d8942017-08-11 12:51:14 -0700141 private static final String IS_EDGE_LINK = "isEdgeLink";
142 private static final String SOURCE_ID = "sourceId";
143 private static final String SOURCE_PORT = "sourcePort";
144 private static final String TARGET_ID = "targetId";
145 private static final String TARGET_PORT = "targetPort";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700146 private static final String APP_ID = "appId";
147 private static final String APP_NAME = "appName";
Simon Huntb745ca62015-07-28 15:37:11 -0700148 private static final String DEVICE = "device";
149 private static final String HOST = "host";
Simon Hunta58d8942017-08-11 12:51:14 -0700150 private static final String LINK = "link";
Simon Huntb745ca62015-07-28 15:37:11 -0700151 private static final String CLASS = "class";
152 private static final String UNKNOWN = "unknown";
153 private static final String ONE = "one";
154 private static final String TWO = "two";
155 private static final String SRC = "src";
156 private static final String DST = "dst";
157 private static final String DATA = "data";
158 private static final String NAME = "name";
159 private static final String NAMES = "names";
160 private static final String ACTIVATE = "activate";
161 private static final String DEACTIVATE = "deactivate";
Viswanath KSP813a20d2016-09-13 04:25:41 +0530162 private static final String PURGE = "purge";
Simon Hunt21281fd2017-03-30 22:28:28 -0700163 private static final String TRAFFIC_TYPE = "trafficType";
Simon Huntb745ca62015-07-28 15:37:11 -0700164
Simon Hunt21281fd2017-03-30 22:28:28 -0700165 // field values
166 private static final String FLOW_STATS_BYTES = "flowStatsBytes";
167 private static final String PORT_STATS_BIT_SEC = "portStatsBitSec";
168 private static final String PORT_STATS_PKT_SEC = "portStatsPktSec";
Simon Huntd2747a02015-04-30 22:41:16 -0700169
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700170 private static final String MY_APP_ID = "org.onosproject.gui";
Thomas Vachuska329af532015-03-10 02:08:33 -0700171
Simon Hunta58d8942017-08-11 12:51:14 -0700172 private static final String SLASH = "/";
173
Simon Hunta17fa672015-08-19 18:42:22 -0700174 private static final long TRAFFIC_PERIOD = 5000;
175 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700176
177 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Simon Hunt8a0429a2017-01-06 16:52:47 -0800178 Comparator.comparing(o -> o.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700179
180
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700181 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700182
183 private static final int MAX_EVENTS = 1000;
184 private static final int MAX_BATCH_MS = 5000;
185 private static final int MAX_IDLE_MS = 1000;
186
187 private ApplicationId appId;
188
189 private final ClusterEventListener clusterListener = new InternalClusterListener();
190 private final MastershipListener mastershipListener = new InternalMastershipListener();
191 private final DeviceListener deviceListener = new InternalDeviceListener();
192 private final LinkListener linkListener = new InternalLinkListener();
193 private final HostListener hostListener = new InternalHostListener();
194 private final IntentListener intentListener = new InternalIntentListener();
195 private final FlowRuleListener flowListener = new InternalFlowListener();
196
197 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700198 private final ExecutorService msgSender =
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700199 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender", log));
Thomas Vachuska329af532015-03-10 02:08:33 -0700200
Simon Hunta17fa672015-08-19 18:42:22 -0700201 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700202 private TrafficMonitor traffic;
Andrea Campanella732ea832017-02-06 09:25:59 -0800203 private ProtectedIntentMonitor protectedIntentMonitor;
Thomas Vachuska329af532015-03-10 02:08:33 -0700204
Simon Huntd2747a02015-04-30 22:41:16 -0700205 private TimerTask summaryTask = null;
206 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700207
Simon Huntd5b96732016-07-08 13:22:27 -0700208 private volatile boolean listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700209
Thomas Vachuska329af532015-03-10 02:08:33 -0700210
211 @Override
212 public void init(UiConnection connection, ServiceDirectory directory) {
213 super.init(connection, directory);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700214 appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
Simon Hunt1911fe42017-05-02 18:25:58 -0700215 traffic = new TrafficMonitor(TRAFFIC_PERIOD, services, this);
216 protectedIntentMonitor = new ProtectedIntentMonitor(TRAFFIC_PERIOD, services, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700217 }
218
219 @Override
220 public void destroy() {
221 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700222 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700223 super.destroy();
224 }
225
Thomas Vachuska329af532015-03-10 02:08:33 -0700226 @Override
Simon Huntda580882015-05-12 20:58:18 -0700227 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700228 return ImmutableSet.of(
229 new TopoStart(),
Simon Hunte05cae42015-07-23 17:35:24 -0700230 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700231 new TopoStop(),
232 new ReqSummary(),
233 new CancelSummary(),
234 new SpriteListReq(),
235 new SpriteDataReq(),
236 new RequestDetails(),
237 new UpdateMeta(),
238 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700239
Simon Huntd2747a02015-04-30 22:41:16 -0700240 // TODO: migrate traffic related to separate app
241 new AddHostIntent(),
242 new AddMultiSourceIntent(),
Viswanath KSP0f297702016-08-13 18:02:43 +0530243 new RemoveIntent(),
Viswanath KSP14aee092016-10-02 01:47:40 +0530244 new ResubmitIntent(),
Deepa Vaddireddy63340922017-01-19 08:15:31 +0530245 new RemoveIntents(),
Simon Hunta17fa672015-08-19 18:42:22 -0700246
Simon Hunt21281fd2017-03-30 22:28:28 -0700247 new ReqAllTraffic(),
Simon Hunta17fa672015-08-19 18:42:22 -0700248 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700249 new ReqRelatedIntents(),
250 new ReqNextIntent(),
251 new ReqPrevIntent(),
252 new ReqSelectedIntentTraffic(),
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700253 new SelIntent(),
Andrea Campanella732ea832017-02-06 09:25:59 -0800254 new SelProtectedIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700255
Andrea Campanella732ea832017-02-06 09:25:59 -0800256 new CancelTraffic(),
257 new CancelProtectedIntentHighlight()
Simon Huntd2747a02015-04-30 22:41:16 -0700258 );
259 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700260
Simon Hunte05cae42015-07-23 17:35:24 -0700261 /**
262 * Injects the topology overlay cache.
263 *
264 * @param overlayCache injected cache
265 */
266 void setOverlayCache(TopoOverlayCache overlayCache) {
267 this.overlayCache = overlayCache;
268 }
269
Simon Huntd2747a02015-04-30 22:41:16 -0700270 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700271
Simon Huntd2747a02015-04-30 22:41:16 -0700272 private final class TopoStart extends RequestHandler {
273 private TopoStart() {
274 super(TOPO_START);
275 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700276
Simon Huntd2747a02015-04-30 22:41:16 -0700277 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800278 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700279 addListeners();
280 sendAllInstances(null);
281 sendAllDevices();
282 sendAllLinks();
283 sendAllHosts();
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700284 sendTopoStartDone();
Thomas Vachuska329af532015-03-10 02:08:33 -0700285 }
286 }
287
Simon Hunte05cae42015-07-23 17:35:24 -0700288 private final class TopoSelectOverlay extends RequestHandler {
289 private TopoSelectOverlay() {
290 super(TOPO_SELECT_OVERLAY);
291 }
292
293 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800294 public void process(ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700295 String deact = string(payload, DEACTIVATE);
296 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700297 overlayCache.switchOverlay(deact, act);
298 }
299 }
300
Simon Huntd2747a02015-04-30 22:41:16 -0700301 private final class TopoStop extends RequestHandler {
302 private TopoStop() {
303 super(TOPO_STOP);
304 }
305
306 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800307 public void process(ObjectNode payload) {
Simon Hunt1ad59272015-11-10 15:23:21 -0800308 removeListeners();
Simon Huntd2747a02015-04-30 22:41:16 -0700309 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700310 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700311 }
312 }
313
314 private final class ReqSummary extends RequestHandler {
315 private ReqSummary() {
316 super(REQ_SUMMARY);
317 }
318
319 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800320 public void process(ObjectNode payload) {
321 requestSummary();
Simon Huntd2747a02015-04-30 22:41:16 -0700322 startSummaryMonitoring();
323 }
324 }
325
326 private final class CancelSummary extends RequestHandler {
327 private CancelSummary() {
328 super(CANCEL_SUMMARY);
329 }
330
331 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800332 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700333 stopSummaryMonitoring();
334 }
335 }
336
337 private final class SpriteListReq extends RequestHandler {
338 private SpriteListReq() {
339 super(SPRITE_LIST_REQ);
340 }
341
342 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800343 public void process(ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700344 ObjectNode root = objectNode();
345 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700346 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700347 root.set(NAMES, names);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800348 sendMessage(SPRITE_LIST_RESPONSE, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700349 }
350 }
351
352 private final class SpriteDataReq extends RequestHandler {
353 private SpriteDataReq() {
354 super(SPRITE_DATA_REQ);
355 }
356
357 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800358 public void process(ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700359 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700360 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700361 root.set(DATA, get(SpriteService.class).get(name));
Simon Hunt8a0429a2017-01-06 16:52:47 -0800362 sendMessage(SPRITE_DATA_RESPONSE, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700363 }
364 }
365
366 private final class RequestDetails extends RequestHandler {
367 private RequestDetails() {
368 super(REQ_DETAILS);
369 }
370
371 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800372 public void process(ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700373 String type = string(payload, CLASS, UNKNOWN);
Simon Hunta58d8942017-08-11 12:51:14 -0700374 String id = string(payload, ID, "");
Simon Huntb745ca62015-07-28 15:37:11 -0700375 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700376
Simon Huntb745ca62015-07-28 15:37:11 -0700377 if (type.equals(DEVICE)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700378 DeviceId did = deviceId(id);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800379 pp = deviceDetails(did);
Simon Huntde99e0b2015-10-23 18:54:06 -0700380 overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
Simon Hunta58d8942017-08-11 12:51:14 -0700381
Simon Huntb745ca62015-07-28 15:37:11 -0700382 } else if (type.equals(HOST)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700383 HostId hid = hostId(id);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800384 pp = hostDetails(hid);
Simon Huntde99e0b2015-10-23 18:54:06 -0700385 overlayCache.currentOverlay().modifyHostDetails(pp, hid);
Simon Hunta58d8942017-08-11 12:51:14 -0700386
387 } else if (type.equals(LINK)) {
388 String srcId = string(payload, SOURCE_ID);
389 String tgtId = string(payload, TARGET_ID);
390 boolean isEdgeLink = bool(payload, IS_EDGE_LINK);
391
392 if (isEdgeLink) {
393 HostId hid = hostId(srcId);
394 String cpstr = tgtId + SLASH + string(payload, TARGET_PORT);
395 ConnectPoint cp = deviceConnectPoint(cpstr);
396
397 pp = edgeLinkDetails(hid, cp);
398 overlayCache.currentOverlay().modifyEdgeLinkDetails(pp, hid, cp);
399
400 } else {
401 String cpAstr = srcId + SLASH + string(payload, SOURCE_PORT);
402 String cpBstr = tgtId + SLASH + string(payload, TARGET_PORT);
403 ConnectPoint cpA = deviceConnectPoint(cpAstr);
404 ConnectPoint cpB = deviceConnectPoint(cpBstr);
405
406 pp = infraLinkDetails(cpA, cpB);
407 overlayCache.currentOverlay().modifyInfraLinkDetails(pp, cpA, cpB);
408 }
Simon Huntd2747a02015-04-30 22:41:16 -0700409 }
Simon Huntb745ca62015-07-28 15:37:11 -0700410
Simon Hunta58d8942017-08-11 12:51:14 -0700411 if (pp != null) {
412 sendMessage(envelope(SHOW_DETAILS, json(pp)));
413 } else {
414 log.warn("Unable to process details request: {}", payload);
415 }
Simon Huntd2747a02015-04-30 22:41:16 -0700416 }
417 }
418
419 private final class UpdateMeta extends RequestHandler {
420 private UpdateMeta() {
421 super(UPDATE_META);
422 }
423
424 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800425 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700426 updateMetaUi(payload);
427 }
428 }
429
430 private final class EqMasters extends RequestHandler {
431 private EqMasters() {
432 super(EQ_MASTERS);
433 }
434
435 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800436 public void process(ObjectNode payload) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700437 services.mastershipAdmin().balanceRoles();
Simon Huntd2747a02015-04-30 22:41:16 -0700438 }
439 }
440
Simon Hunta17fa672015-08-19 18:42:22 -0700441
442 // ========= -----------------------------------------------------------------
443
Simon Huntd2747a02015-04-30 22:41:16 -0700444 // === TODO: move traffic related classes to traffic app
445
446 private final class AddHostIntent extends RequestHandler {
447 private AddHostIntent() {
448 super(ADD_HOST_INTENT);
449 }
450
451 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800452 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700453 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700454 HostId one = hostId(string(payload, ONE));
455 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700456
457 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700458 .appId(appId)
459 .one(one)
460 .two(two)
461 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700462
Simon Hunt1911fe42017-05-02 18:25:58 -0700463 services.intent().submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700464 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
465 traffic.monitor(intent);
466 }
Simon Huntd2747a02015-04-30 22:41:16 -0700467 }
468 }
469
Viswanath KSP0f297702016-08-13 18:02:43 +0530470 private Intent findIntentByPayload(ObjectNode payload) {
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800471 Intent intent;
472 Key key;
Viswanath KSP0f297702016-08-13 18:02:43 +0530473 int appId = Integer.parseInt(string(payload, APP_ID));
474 String appName = string(payload, APP_NAME);
475 ApplicationId applicId = new DefaultApplicationId(appId, appName);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800476 String stringKey = string(payload, KEY);
477 try {
478 // FIXME: If apps use different string key, but they contains
479 // same numeric value (e.g. "020", "0x10", "16", "#10")
480 // and one intent using long key (e.g. 16L)
481 // this function might return wrong intent.
Viswanath KSP0f297702016-08-13 18:02:43 +0530482
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800483 long longKey = Long.decode(stringKey);
484 key = Key.of(longKey, applicId);
Simon Hunt1911fe42017-05-02 18:25:58 -0700485 intent = services.intent().getIntent(key);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800486
487 if (intent == null) {
488 // Intent might using string key, not long key
489 key = Key.of(stringKey, applicId);
Simon Hunt1911fe42017-05-02 18:25:58 -0700490 intent = services.intent().getIntent(key);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800491 }
492 } catch (NumberFormatException ex) {
493 // string key
494 key = Key.of(stringKey, applicId);
Simon Hunt1911fe42017-05-02 18:25:58 -0700495 intent = services.intent().getIntent(key);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800496 }
497
Viswanath KSP0f297702016-08-13 18:02:43 +0530498 log.debug("Attempting to select intent by key={}", key);
499
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800500 return intent;
Viswanath KSP0f297702016-08-13 18:02:43 +0530501 }
502
503 private final class RemoveIntent extends RequestHandler {
504 private RemoveIntent() {
505 super(REMOVE_INTENT);
506 }
507
Viswanath KSP813a20d2016-09-13 04:25:41 +0530508 private boolean isIntentToBePurged(ObjectNode payload) {
509 return bool(payload, PURGE);
510 }
511
Viswanath KSP0f297702016-08-13 18:02:43 +0530512 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800513 public void process(ObjectNode payload) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530514 Intent intent = findIntentByPayload(payload);
515 if (intent == null) {
516 log.warn("Unable to find intent from payload {}", payload);
517 } else {
Viswanath KSP813a20d2016-09-13 04:25:41 +0530518 log.debug("Withdrawing / Purging intent {}", intent.key());
519 if (isIntentToBePurged(payload)) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700520 services.intent().purge(intent);
Viswanath KSP813a20d2016-09-13 04:25:41 +0530521 } else {
Simon Hunt1911fe42017-05-02 18:25:58 -0700522 services.intent().withdraw(intent);
Viswanath KSP813a20d2016-09-13 04:25:41 +0530523 }
Viswanath KSP0f297702016-08-13 18:02:43 +0530524 }
525 }
526 }
527
Viswanath KSP14aee092016-10-02 01:47:40 +0530528 private final class ResubmitIntent extends RequestHandler {
529 private ResubmitIntent() {
530 super(RESUBMIT_INTENT);
531 }
532
533 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800534 public void process(ObjectNode payload) {
Viswanath KSP14aee092016-10-02 01:47:40 +0530535 Intent intent = findIntentByPayload(payload);
536 if (intent == null) {
537 log.warn("Unable to find intent from payload {}", payload);
538 } else {
539 log.debug("Resubmitting intent {}", intent.key());
Simon Hunt1911fe42017-05-02 18:25:58 -0700540 services.intent().submit(intent);
Viswanath KSP14aee092016-10-02 01:47:40 +0530541 }
542 }
543 }
544
Simon Huntd2747a02015-04-30 22:41:16 -0700545 private final class AddMultiSourceIntent extends RequestHandler {
546 private AddMultiSourceIntent() {
547 super(ADD_MULTI_SRC_INTENT);
548 }
549
550 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800551 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700552 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700553 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
554 HostId dst = hostId(string(payload, DST));
Simon Hunt1911fe42017-05-02 18:25:58 -0700555 Host dstHost = services.host().getHost(dst);
Simon Huntd2747a02015-04-30 22:41:16 -0700556
557 Set<ConnectPoint> ingressPoints = getHostLocations(src);
558
559 // FIXME: clearly, this is not enough
560 TrafficSelector selector = DefaultTrafficSelector.builder()
561 .matchEthDst(dstHost.mac()).build();
562 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
563
564 MultiPointToSinglePointIntent intent =
565 MultiPointToSinglePointIntent.builder()
566 .appId(appId)
567 .selector(selector)
568 .treatment(treatment)
569 .ingressPoints(ingressPoints)
570 .egressPoint(dstHost.location())
571 .build();
572
Simon Hunt1911fe42017-05-02 18:25:58 -0700573 services.intent().submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700574 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
575 traffic.monitor(intent);
576 }
Simon Huntd2747a02015-04-30 22:41:16 -0700577 }
578 }
579
Deepa Vaddireddy63340922017-01-19 08:15:31 +0530580 private final class RemoveIntents extends RequestHandler {
581 private RemoveIntents() {
582 super(REMOVE_INTENTS);
583 }
584
585
586 @Override
587 public void process(ObjectNode payload) {
588 IntentService intentService = get(IntentService.class);
589 for (Intent intent : intentService.getIntents()) {
590 if (intentService.getIntentState(intent.key()) == IntentState.WITHDRAWN) {
591 intentService.purge(intent);
592 }
593 }
594
595 }
596 }
597
Simon Hunta17fa672015-08-19 18:42:22 -0700598 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700599
Simon Hunt21281fd2017-03-30 22:28:28 -0700600 private final class ReqAllTraffic extends RequestHandler {
601 private ReqAllTraffic() {
602 super(REQ_ALL_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700603 }
604
605 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800606 public void process(ObjectNode payload) {
Simon Hunt21281fd2017-03-30 22:28:28 -0700607 String trafficType = string(payload, TRAFFIC_TYPE, FLOW_STATS_BYTES);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700608
Simon Hunt21281fd2017-03-30 22:28:28 -0700609 switch (trafficType) {
610 case FLOW_STATS_BYTES:
611 traffic.monitor(Mode.ALL_FLOW_TRAFFIC_BYTES);
612 break;
613 case PORT_STATS_BIT_SEC:
614 traffic.monitor(Mode.ALL_PORT_TRAFFIC_BIT_PS);
615 break;
616 case PORT_STATS_PKT_SEC:
617 traffic.monitor(Mode.ALL_PORT_TRAFFIC_PKT_PS);
618 break;
619 default:
620 break;
621 }
Simon Huntd2747a02015-04-30 22:41:16 -0700622 }
623 }
624
Simon Hunt1911fe42017-05-02 18:25:58 -0700625 private NodeSelection makeNodeSelection(ObjectNode payload) {
626 return new NodeSelection(payload, services.device(), services.host(),
627 services.link());
628 }
629
630
Simon Huntd2747a02015-04-30 22:41:16 -0700631 private final class ReqDevLinkFlows extends RequestHandler {
632 private ReqDevLinkFlows() {
633 super(REQ_DEV_LINK_FLOWS);
634 }
635
636 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800637 public void process(ObjectNode payload) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700638 traffic.monitor(Mode.DEV_LINK_FLOWS, makeNodeSelection(payload));
Simon Hunta17fa672015-08-19 18:42:22 -0700639 }
640 }
641
642 private final class ReqRelatedIntents extends RequestHandler {
643 private ReqRelatedIntents() {
644 super(REQ_RELATED_INTENTS);
645 }
646
647 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800648 public void process(ObjectNode payload) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700649 traffic.monitor(Mode.RELATED_INTENTS, makeNodeSelection(payload));
Simon Hunta17fa672015-08-19 18:42:22 -0700650 }
651 }
652
653 private final class ReqNextIntent extends RequestHandler {
654 private ReqNextIntent() {
655 super(REQ_NEXT_INTENT);
656 }
657
658 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800659 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700660 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700661 }
662 }
663
664 private final class ReqPrevIntent extends RequestHandler {
665 private ReqPrevIntent() {
666 super(REQ_PREV_INTENT);
667 }
668
669 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800670 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700671 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700672 }
673 }
674
675 private final class ReqSelectedIntentTraffic extends RequestHandler {
676 private ReqSelectedIntentTraffic() {
677 super(REQ_SEL_INTENT_TRAFFIC);
678 }
679
680 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800681 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700682 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700683 }
684 }
685
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700686 private final class SelIntent extends RequestHandler {
687 private SelIntent() {
688 super(SEL_INTENT);
689 }
690
691 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800692 public void process(ObjectNode payload) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530693 Intent intent = findIntentByPayload(payload);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700694 if (intent == null) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530695 log.warn("Unable to find intent from payload {}", payload);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700696 } else {
Viswanath KSP0f297702016-08-13 18:02:43 +0530697 log.debug("starting to monitor intent {}", intent.key());
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700698 traffic.monitor(intent);
699 }
700 }
701 }
702
Andrea Campanella732ea832017-02-06 09:25:59 -0800703 private final class SelProtectedIntent extends RequestHandler {
704 private SelProtectedIntent() {
705 super(SEL_PROTECTED_INTENT);
706 }
707
708 @Override
709 public void process(ObjectNode payload) {
710 Intent intent = findIntentByPayload(payload);
711 if (intent == null) {
712 log.warn("Unable to find protected intent from payload {}", payload);
713 } else {
714 log.debug("starting to monitor protected intent {}", intent.key());
715 protectedIntentMonitor.monitor(intent);
716 }
717 }
718 }
719
Simon Huntd2747a02015-04-30 22:41:16 -0700720 private final class CancelTraffic extends RequestHandler {
721 private CancelTraffic() {
722 super(CANCEL_TRAFFIC);
723 }
724
725 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800726 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700727 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700728 }
729 }
730
Andrea Campanella732ea832017-02-06 09:25:59 -0800731 private final class CancelProtectedIntentHighlight extends RequestHandler {
732 private CancelProtectedIntentHighlight() {
733 super(CANCEL_PROTECTED_INTENT_HIGHLIGHT);
734 }
735
736 @Override
737 public void process(ObjectNode payload) {
738 protectedIntentMonitor.stopMonitoring();
739 }
740 }
741
Simon Huntd2747a02015-04-30 22:41:16 -0700742 //=======================================================================
743
Simon Hunta17fa672015-08-19 18:42:22 -0700744 // Converts highlights to JSON format and sends the message to the client
Simon Hunt8a0429a2017-01-06 16:52:47 -0800745 void sendHighlights(Highlights highlights) {
Simon Hunt52560662015-08-27 22:46:44 -0700746 sendMessage(highlightsMessage(highlights));
Thomas Vachuska329af532015-03-10 02:08:33 -0700747 }
748
Simon Huntd2747a02015-04-30 22:41:16 -0700749 // Subscribes for summary messages.
Simon Hunt8a0429a2017-01-06 16:52:47 -0800750 private synchronized void requestSummary() {
751 PropertyPanel pp = summmaryMessage();
Simon Hunt0af1ec32015-07-24 12:17:55 -0700752 overlayCache.currentOverlay().modifySummary(pp);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800753 sendMessage(envelope(SHOW_SUMMARY, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700754 }
755
Simon Huntd2747a02015-04-30 22:41:16 -0700756
Thomas Vachuska329af532015-03-10 02:08:33 -0700757 private void cancelAllRequests() {
758 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700759 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700760 }
761
762 // Sends all controller nodes to the client as node-added messages.
763 private void sendAllInstances(String messageType) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700764 List<ControllerNode> nodes = new ArrayList<>(services.cluster().getNodes());
Simon Hunt8a0429a2017-01-06 16:52:47 -0800765 nodes.sort(NODE_COMPARATOR);
Thomas Vachuska329af532015-03-10 02:08:33 -0700766 for (ControllerNode node : nodes) {
767 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
Andrea Campanella732ea832017-02-06 09:25:59 -0800768 messageType));
Thomas Vachuska329af532015-03-10 02:08:33 -0700769 }
770 }
771
772 // Sends all devices to the client as device-added messages.
773 private void sendAllDevices() {
774 // Send optical first, others later for layered rendering
Simon Hunt1911fe42017-05-02 18:25:58 -0700775 for (Device device : services.device().getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200776 if ((device.type() == Device.Type.ROADM) ||
Simon Hunt5c1a9382016-06-01 19:35:35 -0700777 (device.type() == Device.Type.OTN)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700778 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
779 }
780 }
Simon Hunt1911fe42017-05-02 18:25:58 -0700781 for (Device device : services.device().getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200782 if ((device.type() != Device.Type.ROADM) &&
Simon Hunt5c1a9382016-06-01 19:35:35 -0700783 (device.type() != Device.Type.OTN)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700784 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
785 }
786 }
787 }
788
789 // Sends all links to the client as link-added messages.
790 private void sendAllLinks() {
791 // Send optical first, others later for layered rendering
Simon Hunt1911fe42017-05-02 18:25:58 -0700792 for (Link link : services.link().getLinks()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700793 if (link.type() == Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700794 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700795 }
796 }
Simon Hunt1911fe42017-05-02 18:25:58 -0700797 for (Link link : services.link().getLinks()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700798 if (link.type() != Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700799 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700800 }
801 }
802 }
803
Simon Hunt5c1a9382016-06-01 19:35:35 -0700804 // Temporary mechanism to support topology overlays adding their own
805 // properties to the link events.
806 private ObjectNode composeLinkMessage(LinkEvent event) {
807 // start with base message
808 ObjectNode msg = linkMessage(event);
809 Map<String, String> additional =
810 overlayCache.currentOverlay().additionalLinkData(event);
811
812 if (additional != null) {
813 // attach additional key-value pairs as extra data structure
814 ObjectNode payload = (ObjectNode) msg.get(PAYLOAD);
815 payload.set(EXTRA, createExtra(additional));
816 }
817 return msg;
818 }
819
820 private ObjectNode createExtra(Map<String, String> additional) {
821 ObjectNode extra = objectNode();
822 for (Map.Entry<String, String> entry : additional.entrySet()) {
823 extra.put(entry.getKey(), entry.getValue());
824 }
825 return extra;
826 }
827
Thomas Vachuska329af532015-03-10 02:08:33 -0700828 // Sends all hosts to the client as host-added messages.
829 private void sendAllHosts() {
Simon Hunt1911fe42017-05-02 18:25:58 -0700830 for (Host host : services.host().getHosts()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700831 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
832 }
833 }
834
Thomas Vachuska329af532015-03-10 02:08:33 -0700835 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
836 Set<ConnectPoint> points = new HashSet<>();
837 for (HostId hostId : hostIds) {
838 points.add(getHostLocation(hostId));
839 }
840 return points;
841 }
842
843 private HostLocation getHostLocation(HostId hostId) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700844 return services.host().getHost(hostId).location();
Thomas Vachuska329af532015-03-10 02:08:33 -0700845 }
846
847 // Produces a list of host ids from the specified JSON array.
848 private Set<HostId> getHostIds(ArrayNode ids) {
849 Set<HostId> hostIds = new HashSet<>();
850 for (JsonNode id : ids) {
851 hostIds.add(hostId(id.asText()));
852 }
853 return hostIds;
854 }
855
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700856 private void sendTopoStartDone() {
857 sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode()));
858 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700859
Simon Huntd2747a02015-04-30 22:41:16 -0700860 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700861 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700862 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700863 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700864 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700865 }
866
867 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700868 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700869 summaryTask.cancel();
870 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700871 }
Simon Huntd2747a02015-04-30 22:41:16 -0700872 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700873 }
874
Thomas Vachuska329af532015-03-10 02:08:33 -0700875
876 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700877 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700878 listenersRemoved = false;
Simon Hunt1911fe42017-05-02 18:25:58 -0700879 services.cluster().addListener(clusterListener);
880 services.mastership().addListener(mastershipListener);
881 services.device().addListener(deviceListener);
882 services.link().addListener(linkListener);
883 services.host().addListener(hostListener);
884 services.intent().addListener(intentListener);
885 services.flow().addListener(flowListener);
Thomas Vachuska329af532015-03-10 02:08:33 -0700886 }
887
888 // Removes all internal listeners.
889 private synchronized void removeListeners() {
890 if (!listenersRemoved) {
891 listenersRemoved = true;
Simon Hunt1911fe42017-05-02 18:25:58 -0700892 services.cluster().removeListener(clusterListener);
893 services.mastership().removeListener(mastershipListener);
894 services.device().removeListener(deviceListener);
895 services.link().removeListener(linkListener);
896 services.host().removeListener(hostListener);
897 services.intent().removeListener(intentListener);
898 services.flow().removeListener(flowListener);
Thomas Vachuska329af532015-03-10 02:08:33 -0700899 }
900 }
901
902 // Cluster event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700903 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
904 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700905 private class InternalClusterListener implements ClusterEventListener {
906 @Override
907 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700908 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700909 }
910 }
911
912 // Mastership change listener
Simon Hunt7092cc42016-04-06 18:40:17 -0700913 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
914 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700915 private class InternalMastershipListener implements MastershipListener {
916 @Override
917 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700918 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700919 sendAllInstances(UPDATE_INSTANCE);
Simon Hunt1911fe42017-05-02 18:25:58 -0700920 Device device = services.device().getDevice(event.subject());
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700921 if (device != null) {
922 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
923 }
924 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700925 }
926 }
927
928 // Device event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700929 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
930 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700931 private class InternalDeviceListener implements DeviceListener {
932 @Override
933 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700934 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700935 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800936 msgSender.execute(traffic::pokeIntent);
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700937 eventAccummulator.add(event);
938 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700939 }
940 }
941
942 // Link event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700943 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
944 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700945 private class InternalLinkListener implements LinkListener {
946 @Override
947 public void event(LinkEvent event) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700948 msgSender.execute(() -> sendMessage(composeLinkMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800949 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700950 eventAccummulator.add(event);
951 }
952 }
953
954 // Host event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700955 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
956 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700957 private class InternalHostListener implements HostListener {
958 @Override
959 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700960 msgSender.execute(() -> sendMessage(hostMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800961 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700962 eventAccummulator.add(event);
963 }
964 }
965
966 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700967 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
968 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700969 private class InternalIntentListener implements IntentListener {
970 @Override
971 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700972 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700973 eventAccummulator.add(event);
974 }
975 }
976
977 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700978 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
979 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700980 private class InternalFlowListener implements FlowRuleListener {
981 @Override
982 public void event(FlowRuleEvent event) {
983 eventAccummulator.add(event);
984 }
985 }
986
Simon Huntd2747a02015-04-30 22:41:16 -0700987
Simon Hunta17fa672015-08-19 18:42:22 -0700988 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700989
990 // Periodic update of the summary information
991 private class SummaryMonitor extends TimerTask {
992 @Override
993 public void run() {
994 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700995 if (summaryRunning) {
Simon Hunt8a0429a2017-01-06 16:52:47 -0800996 msgSender.execute(() -> requestSummary());
Thomas Vachuska329af532015-03-10 02:08:33 -0700997 }
998 } catch (Exception e) {
999 log.warn("Unable to handle summary request due to {}", e.getMessage());
1000 log.warn("Boom!", e);
1001 }
1002 }
1003 }
1004
1005 // Accumulates events to drive methodic update of the summary pane.
1006 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
1007 protected InternalEventAccummulator() {
1008 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
1009 }
1010
1011 @Override
1012 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -07001013 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -07001014 long now = System.currentTimeMillis();
1015 String me = this.toString();
1016 String miniMe = me.replaceAll("^.*@", "me@");
1017 log.debug("Time: {}; this: {}, processing items ({} events)",
Andrea Campanella732ea832017-02-06 09:25:59 -08001018 now, miniMe, items.size());
Simon Hunt8d22c4b2015-08-06 16:24:43 -07001019 // End-of-Debugging
1020
Thomas Vachuska329af532015-03-10 02:08:33 -07001021 try {
Simon Huntd2747a02015-04-30 22:41:16 -07001022 if (summaryRunning) {
Simon Hunt8a0429a2017-01-06 16:52:47 -08001023 msgSender.execute(() -> requestSummary());
Thomas Vachuska329af532015-03-10 02:08:33 -07001024 }
1025 } catch (Exception e) {
1026 log.warn("Unable to handle summary request due to {}", e.getMessage());
1027 log.debug("Boom!", e);
1028 }
1029 }
1030 }
1031}