blob: cae4760d812cb8de6d3abeaa0d265a4b14af8789 [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;
Ray Milkey27cff8c2018-03-05 14:58:26 -080037import org.onosproject.net.FilteredConnectPoint;
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;
Deepa Vaddireddy63340922017-01-19 08:15:31 +053056import org.onosproject.net.intent.IntentService;
Andrea Campanella732ea832017-02-06 09:25:59 -080057import org.onosproject.net.intent.IntentState;
Simon Hunt21281fd2017-03-30 22:28:28 -070058import org.onosproject.net.intent.Key;
59import org.onosproject.net.intent.MultiPointToSinglePointIntent;
Thomas Vachuska329af532015-03-10 02:08:33 -070060import org.onosproject.net.link.LinkEvent;
61import org.onosproject.net.link.LinkListener;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070062import org.onosproject.ui.JsonUtils;
Simon Huntd2747a02015-04-30 22:41:16 -070063import org.onosproject.ui.RequestHandler;
Thomas Vachuska329af532015-03-10 02:08:33 -070064import org.onosproject.ui.UiConnection;
Simon Hunt1911fe42017-05-02 18:25:58 -070065import org.onosproject.ui.impl.TrafficMonitorBase.Mode;
Simon Hunta17fa672015-08-19 18:42:22 -070066import org.onosproject.ui.topo.Highlights;
Simon Huntd3ceffa2015-08-25 12:44:35 -070067import org.onosproject.ui.topo.NodeSelection;
Simon Hunt0af1ec32015-07-24 12:17:55 -070068import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070069
70import java.util.ArrayList;
Simon Huntd2747a02015-04-30 22:41:16 -070071import java.util.Collection;
Thomas Vachuska329af532015-03-10 02:08:33 -070072import java.util.Comparator;
73import java.util.HashSet;
74import java.util.List;
Simon Hunt5c1a9382016-06-01 19:35:35 -070075import java.util.Map;
Thomas Vachuska329af532015-03-10 02:08:33 -070076import java.util.Set;
77import java.util.Timer;
78import java.util.TimerTask;
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070079import java.util.concurrent.ExecutorService;
Thomas Vachuska329af532015-03-10 02:08:33 -070080
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070081import static java.util.concurrent.Executors.newSingleThreadExecutor;
82import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska329af532015-03-10 02:08:33 -070083import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
Simon Hunta58d8942017-08-11 12:51:14 -070084import static org.onosproject.net.ConnectPoint.deviceConnectPoint;
Thomas Vachuska329af532015-03-10 02:08:33 -070085import static org.onosproject.net.DeviceId.deviceId;
86import static org.onosproject.net.HostId.hostId;
Simon Hunt879ce452017-08-10 23:32:00 -070087import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
88import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
89import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
Thomas Vachuska329af532015-03-10 02:08:33 -070090import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
91import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntd3ceffa2015-08-25 12:44:35 -070092import static org.onosproject.ui.JsonUtils.envelope;
Viswanath KSP0f297702016-08-13 18:02:43 +053093import static org.onosproject.ui.JsonUtils.string;
Simon Hunt52560662015-08-27 22:46:44 -070094import static org.onosproject.ui.topo.TopoJson.highlightsMessage;
95import static org.onosproject.ui.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070096
97/**
98 * Web socket capable of interacting with the GUI topology view.
99 */
100public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
101
Simon Huntb745ca62015-07-28 15:37:11 -0700102 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -0700103 private static final String REQ_DETAILS = "requestDetails";
104 private static final String UPDATE_META = "updateMeta";
105 private static final String ADD_HOST_INTENT = "addHostIntent";
Viswanath KSP0f297702016-08-13 18:02:43 +0530106 private static final String REMOVE_INTENT = "removeIntent";
Deepa Vaddireddy63340922017-01-19 08:15:31 +0530107 private static final String REMOVE_INTENTS = "removeIntents";
Viswanath KSP14aee092016-10-02 01:47:40 +0530108 private static final String RESUBMIT_INTENT = "resubmitIntent";
Simon Huntd2747a02015-04-30 22:41:16 -0700109 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
110 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
111 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
112 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
113 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700114 private static final String SEL_INTENT = "selectIntent";
Simon Hunt21281fd2017-03-30 22:28:28 -0700115 private static final String REQ_ALL_TRAFFIC = "requestAllTraffic";
Thomas Vachuska2b4de872021-03-30 16:31:34 -0700116 private static final String REQ_CUSTOM_TRAFFIC = "requestCustomTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700117 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
118 private static final String CANCEL_TRAFFIC = "cancelTraffic";
119 private static final String REQ_SUMMARY = "requestSummary";
120 private static final String CANCEL_SUMMARY = "cancelSummary";
121 private static final String EQ_MASTERS = "equalizeMasters";
122 private static final String SPRITE_LIST_REQ = "spriteListRequest";
123 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
124 private static final String TOPO_START = "topoStart";
Simon Hunte05cae42015-07-23 17:35:24 -0700125 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700126 private static final String TOPO_STOP = "topoStop";
Andrea Campanella732ea832017-02-06 09:25:59 -0800127 private static final String SEL_PROTECTED_INTENT = "selectProtectedIntent";
128 private static final String CANCEL_PROTECTED_INTENT_HIGHLIGHT = "cancelProtectedIntentHighlight";
129
Simon Huntb745ca62015-07-28 15:37:11 -0700130 // outgoing event types
131 private static final String SHOW_SUMMARY = "showSummary";
132 private static final String SHOW_DETAILS = "showDetails";
133 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
134 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
135 private static final String UPDATE_INSTANCE = "updateInstance";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700136 private static final String TOPO_START_DONE = "topoStartDone";
Simon Huntb745ca62015-07-28 15:37:11 -0700137
138 // fields
Simon Hunt5c1a9382016-06-01 19:35:35 -0700139 private static final String PAYLOAD = "payload";
140 private static final String EXTRA = "extra";
Simon Huntb745ca62015-07-28 15:37:11 -0700141 private static final String ID = "id";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700142 private static final String KEY = "key";
Simon Hunta58d8942017-08-11 12:51:14 -0700143 private static final String IS_EDGE_LINK = "isEdgeLink";
144 private static final String SOURCE_ID = "sourceId";
145 private static final String SOURCE_PORT = "sourcePort";
146 private static final String TARGET_ID = "targetId";
147 private static final String TARGET_PORT = "targetPort";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700148 private static final String APP_ID = "appId";
149 private static final String APP_NAME = "appName";
Simon Huntb745ca62015-07-28 15:37:11 -0700150 private static final String DEVICE = "device";
151 private static final String HOST = "host";
Simon Hunta58d8942017-08-11 12:51:14 -0700152 private static final String LINK = "link";
Simon Huntb745ca62015-07-28 15:37:11 -0700153 private static final String CLASS = "class";
154 private static final String UNKNOWN = "unknown";
155 private static final String ONE = "one";
156 private static final String TWO = "two";
157 private static final String SRC = "src";
158 private static final String DST = "dst";
159 private static final String DATA = "data";
160 private static final String NAME = "name";
161 private static final String NAMES = "names";
162 private static final String ACTIVATE = "activate";
163 private static final String DEACTIVATE = "deactivate";
Viswanath KSP813a20d2016-09-13 04:25:41 +0530164 private static final String PURGE = "purge";
Simon Hunt21281fd2017-03-30 22:28:28 -0700165 private static final String TRAFFIC_TYPE = "trafficType";
Simon Huntb745ca62015-07-28 15:37:11 -0700166
Simon Hunt21281fd2017-03-30 22:28:28 -0700167 // field values
168 private static final String FLOW_STATS_BYTES = "flowStatsBytes";
169 private static final String PORT_STATS_BIT_SEC = "portStatsBitSec";
170 private static final String PORT_STATS_PKT_SEC = "portStatsPktSec";
Simon Huntd2747a02015-04-30 22:41:16 -0700171
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700172 private static final String MY_APP_ID = "org.onosproject.gui";
Thomas Vachuska329af532015-03-10 02:08:33 -0700173
Simon Hunta58d8942017-08-11 12:51:14 -0700174 private static final String SLASH = "/";
175
Simon Hunta17fa672015-08-19 18:42:22 -0700176 private static final long TRAFFIC_PERIOD = 5000;
177 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700178
179 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Simon Hunt8a0429a2017-01-06 16:52:47 -0800180 Comparator.comparing(o -> o.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700181
182
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700183 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700184
185 private static final int MAX_EVENTS = 1000;
186 private static final int MAX_BATCH_MS = 5000;
187 private static final int MAX_IDLE_MS = 1000;
188
189 private ApplicationId appId;
190
191 private final ClusterEventListener clusterListener = new InternalClusterListener();
192 private final MastershipListener mastershipListener = new InternalMastershipListener();
193 private final DeviceListener deviceListener = new InternalDeviceListener();
194 private final LinkListener linkListener = new InternalLinkListener();
195 private final HostListener hostListener = new InternalHostListener();
196 private final IntentListener intentListener = new InternalIntentListener();
197 private final FlowRuleListener flowListener = new InternalFlowListener();
198
199 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700200 private final ExecutorService msgSender =
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700201 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender", log));
Thomas Vachuska329af532015-03-10 02:08:33 -0700202
Simon Hunta17fa672015-08-19 18:42:22 -0700203 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700204 private TrafficMonitor traffic;
Andrea Campanella732ea832017-02-06 09:25:59 -0800205 private ProtectedIntentMonitor protectedIntentMonitor;
Thomas Vachuska329af532015-03-10 02:08:33 -0700206
Simon Huntd2747a02015-04-30 22:41:16 -0700207 private TimerTask summaryTask = null;
208 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700209
Simon Huntd5b96732016-07-08 13:22:27 -0700210 private volatile boolean listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700211
Thomas Vachuska329af532015-03-10 02:08:33 -0700212
213 @Override
214 public void init(UiConnection connection, ServiceDirectory directory) {
215 super.init(connection, directory);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700216 appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
Simon Hunt1911fe42017-05-02 18:25:58 -0700217 traffic = new TrafficMonitor(TRAFFIC_PERIOD, services, this);
218 protectedIntentMonitor = new ProtectedIntentMonitor(TRAFFIC_PERIOD, services, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700219 }
220
221 @Override
222 public void destroy() {
223 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700224 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700225 super.destroy();
226 }
227
Thomas Vachuska329af532015-03-10 02:08:33 -0700228 @Override
Simon Huntda580882015-05-12 20:58:18 -0700229 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700230 return ImmutableSet.of(
231 new TopoStart(),
Simon Hunte05cae42015-07-23 17:35:24 -0700232 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700233 new TopoStop(),
234 new ReqSummary(),
235 new CancelSummary(),
236 new SpriteListReq(),
237 new SpriteDataReq(),
238 new RequestDetails(),
239 new UpdateMeta(),
240 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700241
Simon Huntd2747a02015-04-30 22:41:16 -0700242 // TODO: migrate traffic related to separate app
243 new AddHostIntent(),
244 new AddMultiSourceIntent(),
Viswanath KSP0f297702016-08-13 18:02:43 +0530245 new RemoveIntent(),
Viswanath KSP14aee092016-10-02 01:47:40 +0530246 new ResubmitIntent(),
Deepa Vaddireddy63340922017-01-19 08:15:31 +0530247 new RemoveIntents(),
Simon Hunta17fa672015-08-19 18:42:22 -0700248
Simon Hunt21281fd2017-03-30 22:28:28 -0700249 new ReqAllTraffic(),
Thomas Vachuska2b4de872021-03-30 16:31:34 -0700250 new ReqCustomTraffic(),
Simon Hunta17fa672015-08-19 18:42:22 -0700251 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700252 new ReqRelatedIntents(),
253 new ReqNextIntent(),
254 new ReqPrevIntent(),
255 new ReqSelectedIntentTraffic(),
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700256 new SelIntent(),
Andrea Campanella732ea832017-02-06 09:25:59 -0800257 new SelProtectedIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700258
Andrea Campanella732ea832017-02-06 09:25:59 -0800259 new CancelTraffic(),
260 new CancelProtectedIntentHighlight()
Simon Huntd2747a02015-04-30 22:41:16 -0700261 );
262 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700263
Simon Hunte05cae42015-07-23 17:35:24 -0700264 /**
265 * Injects the topology overlay cache.
266 *
267 * @param overlayCache injected cache
268 */
269 void setOverlayCache(TopoOverlayCache overlayCache) {
270 this.overlayCache = overlayCache;
271 }
272
Simon Huntd2747a02015-04-30 22:41:16 -0700273 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700274
Simon Huntd2747a02015-04-30 22:41:16 -0700275 private final class TopoStart extends RequestHandler {
276 private TopoStart() {
277 super(TOPO_START);
278 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700279
Simon Huntd2747a02015-04-30 22:41:16 -0700280 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800281 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700282 addListeners();
283 sendAllInstances(null);
284 sendAllDevices();
285 sendAllLinks();
286 sendAllHosts();
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700287 sendTopoStartDone();
Thomas Vachuska329af532015-03-10 02:08:33 -0700288 }
289 }
290
Simon Hunte05cae42015-07-23 17:35:24 -0700291 private final class TopoSelectOverlay extends RequestHandler {
292 private TopoSelectOverlay() {
293 super(TOPO_SELECT_OVERLAY);
294 }
295
296 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800297 public void process(ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700298 String deact = string(payload, DEACTIVATE);
299 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700300 overlayCache.switchOverlay(deact, act);
301 }
302 }
303
Simon Huntd2747a02015-04-30 22:41:16 -0700304 private final class TopoStop extends RequestHandler {
305 private TopoStop() {
306 super(TOPO_STOP);
307 }
308
309 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800310 public void process(ObjectNode payload) {
Simon Hunt1ad59272015-11-10 15:23:21 -0800311 removeListeners();
Simon Huntd2747a02015-04-30 22:41:16 -0700312 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700313 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700314 }
315 }
316
317 private final class ReqSummary extends RequestHandler {
318 private ReqSummary() {
319 super(REQ_SUMMARY);
320 }
321
322 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800323 public void process(ObjectNode payload) {
324 requestSummary();
Simon Huntd2747a02015-04-30 22:41:16 -0700325 startSummaryMonitoring();
326 }
327 }
328
329 private final class CancelSummary extends RequestHandler {
330 private CancelSummary() {
331 super(CANCEL_SUMMARY);
332 }
333
334 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800335 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700336 stopSummaryMonitoring();
337 }
338 }
339
340 private final class SpriteListReq extends RequestHandler {
341 private SpriteListReq() {
342 super(SPRITE_LIST_REQ);
343 }
344
345 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800346 public void process(ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700347 ObjectNode root = objectNode();
348 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700349 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700350 root.set(NAMES, names);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800351 sendMessage(SPRITE_LIST_RESPONSE, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700352 }
353 }
354
355 private final class SpriteDataReq extends RequestHandler {
356 private SpriteDataReq() {
357 super(SPRITE_DATA_REQ);
358 }
359
360 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800361 public void process(ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700362 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700363 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700364 root.set(DATA, get(SpriteService.class).get(name));
Simon Hunt8a0429a2017-01-06 16:52:47 -0800365 sendMessage(SPRITE_DATA_RESPONSE, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700366 }
367 }
368
369 private final class RequestDetails extends RequestHandler {
370 private RequestDetails() {
371 super(REQ_DETAILS);
372 }
373
374 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800375 public void process(ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700376 String type = string(payload, CLASS, UNKNOWN);
Simon Hunta58d8942017-08-11 12:51:14 -0700377 String id = string(payload, ID, "");
Simon Huntb745ca62015-07-28 15:37:11 -0700378 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700379
Simon Huntb745ca62015-07-28 15:37:11 -0700380 if (type.equals(DEVICE)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700381 DeviceId did = deviceId(id);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800382 pp = deviceDetails(did);
Simon Huntde99e0b2015-10-23 18:54:06 -0700383 overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
Simon Hunta58d8942017-08-11 12:51:14 -0700384
Simon Huntb745ca62015-07-28 15:37:11 -0700385 } else if (type.equals(HOST)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700386 HostId hid = hostId(id);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800387 pp = hostDetails(hid);
Simon Huntde99e0b2015-10-23 18:54:06 -0700388 overlayCache.currentOverlay().modifyHostDetails(pp, hid);
Simon Hunta58d8942017-08-11 12:51:14 -0700389
390 } else if (type.equals(LINK)) {
391 String srcId = string(payload, SOURCE_ID);
392 String tgtId = string(payload, TARGET_ID);
393 boolean isEdgeLink = bool(payload, IS_EDGE_LINK);
394
395 if (isEdgeLink) {
396 HostId hid = hostId(srcId);
397 String cpstr = tgtId + SLASH + string(payload, TARGET_PORT);
398 ConnectPoint cp = deviceConnectPoint(cpstr);
399
400 pp = edgeLinkDetails(hid, cp);
401 overlayCache.currentOverlay().modifyEdgeLinkDetails(pp, hid, cp);
402
403 } else {
404 String cpAstr = srcId + SLASH + string(payload, SOURCE_PORT);
405 String cpBstr = tgtId + SLASH + string(payload, TARGET_PORT);
406 ConnectPoint cpA = deviceConnectPoint(cpAstr);
407 ConnectPoint cpB = deviceConnectPoint(cpBstr);
408
409 pp = infraLinkDetails(cpA, cpB);
410 overlayCache.currentOverlay().modifyInfraLinkDetails(pp, cpA, cpB);
411 }
Simon Huntd2747a02015-04-30 22:41:16 -0700412 }
Simon Huntb745ca62015-07-28 15:37:11 -0700413
Simon Hunta58d8942017-08-11 12:51:14 -0700414 if (pp != null) {
415 sendMessage(envelope(SHOW_DETAILS, json(pp)));
416 } else {
417 log.warn("Unable to process details request: {}", payload);
418 }
Simon Huntd2747a02015-04-30 22:41:16 -0700419 }
420 }
421
422 private final class UpdateMeta extends RequestHandler {
423 private UpdateMeta() {
424 super(UPDATE_META);
425 }
426
427 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800428 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700429 updateMetaUi(payload);
430 }
431 }
432
433 private final class EqMasters extends RequestHandler {
434 private EqMasters() {
435 super(EQ_MASTERS);
436 }
437
438 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800439 public void process(ObjectNode payload) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700440 services.mastershipAdmin().balanceRoles();
Simon Huntd2747a02015-04-30 22:41:16 -0700441 }
442 }
443
Simon Hunta17fa672015-08-19 18:42:22 -0700444
445 // ========= -----------------------------------------------------------------
446
Simon Huntd2747a02015-04-30 22:41:16 -0700447 // === TODO: move traffic related classes to traffic app
448
449 private final class AddHostIntent extends RequestHandler {
450 private AddHostIntent() {
451 super(ADD_HOST_INTENT);
452 }
453
454 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800455 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700456 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700457 HostId one = hostId(string(payload, ONE));
458 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700459
460 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700461 .appId(appId)
462 .one(one)
463 .two(two)
464 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700465
Simon Hunt1911fe42017-05-02 18:25:58 -0700466 services.intent().submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700467 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
468 traffic.monitor(intent);
469 }
Simon Huntd2747a02015-04-30 22:41:16 -0700470 }
471 }
472
Viswanath KSP0f297702016-08-13 18:02:43 +0530473 private Intent findIntentByPayload(ObjectNode payload) {
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800474 Intent intent;
475 Key key;
Viswanath KSP0f297702016-08-13 18:02:43 +0530476 int appId = Integer.parseInt(string(payload, APP_ID));
477 String appName = string(payload, APP_NAME);
478 ApplicationId applicId = new DefaultApplicationId(appId, appName);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800479 String stringKey = string(payload, KEY);
480 try {
481 // FIXME: If apps use different string key, but they contains
482 // same numeric value (e.g. "020", "0x10", "16", "#10")
483 // and one intent using long key (e.g. 16L)
484 // this function might return wrong intent.
Viswanath KSP0f297702016-08-13 18:02:43 +0530485
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800486 long longKey = Long.decode(stringKey);
487 key = Key.of(longKey, applicId);
Simon Hunt1911fe42017-05-02 18:25:58 -0700488 intent = services.intent().getIntent(key);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800489
490 if (intent == null) {
491 // Intent might using string key, not long key
492 key = Key.of(stringKey, applicId);
Simon Hunt1911fe42017-05-02 18:25:58 -0700493 intent = services.intent().getIntent(key);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800494 }
495 } catch (NumberFormatException ex) {
496 // string key
497 key = Key.of(stringKey, applicId);
Simon Hunt1911fe42017-05-02 18:25:58 -0700498 intent = services.intent().getIntent(key);
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800499 }
500
Viswanath KSP0f297702016-08-13 18:02:43 +0530501 log.debug("Attempting to select intent by key={}", key);
502
Yi Tseng3a9b01c2017-02-16 14:24:28 -0800503 return intent;
Viswanath KSP0f297702016-08-13 18:02:43 +0530504 }
505
506 private final class RemoveIntent extends RequestHandler {
507 private RemoveIntent() {
508 super(REMOVE_INTENT);
509 }
510
Viswanath KSP813a20d2016-09-13 04:25:41 +0530511 private boolean isIntentToBePurged(ObjectNode payload) {
512 return bool(payload, PURGE);
513 }
514
Viswanath KSP0f297702016-08-13 18:02:43 +0530515 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800516 public void process(ObjectNode payload) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530517 Intent intent = findIntentByPayload(payload);
518 if (intent == null) {
519 log.warn("Unable to find intent from payload {}", payload);
520 } else {
Viswanath KSP813a20d2016-09-13 04:25:41 +0530521 log.debug("Withdrawing / Purging intent {}", intent.key());
522 if (isIntentToBePurged(payload)) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700523 services.intent().purge(intent);
Viswanath KSP813a20d2016-09-13 04:25:41 +0530524 } else {
Simon Hunt1911fe42017-05-02 18:25:58 -0700525 services.intent().withdraw(intent);
Viswanath KSP813a20d2016-09-13 04:25:41 +0530526 }
Viswanath KSP0f297702016-08-13 18:02:43 +0530527 }
528 }
529 }
530
Viswanath KSP14aee092016-10-02 01:47:40 +0530531 private final class ResubmitIntent extends RequestHandler {
532 private ResubmitIntent() {
533 super(RESUBMIT_INTENT);
534 }
535
536 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800537 public void process(ObjectNode payload) {
Viswanath KSP14aee092016-10-02 01:47:40 +0530538 Intent intent = findIntentByPayload(payload);
539 if (intent == null) {
540 log.warn("Unable to find intent from payload {}", payload);
541 } else {
542 log.debug("Resubmitting intent {}", intent.key());
Simon Hunt1911fe42017-05-02 18:25:58 -0700543 services.intent().submit(intent);
Viswanath KSP14aee092016-10-02 01:47:40 +0530544 }
545 }
546 }
547
Simon Huntd2747a02015-04-30 22:41:16 -0700548 private final class AddMultiSourceIntent extends RequestHandler {
549 private AddMultiSourceIntent() {
550 super(ADD_MULTI_SRC_INTENT);
551 }
552
553 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800554 public void process(ObjectNode payload) {
Simon Huntd2747a02015-04-30 22:41:16 -0700555 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700556 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
557 HostId dst = hostId(string(payload, DST));
Simon Hunt1911fe42017-05-02 18:25:58 -0700558 Host dstHost = services.host().getHost(dst);
Simon Huntd2747a02015-04-30 22:41:16 -0700559
Ray Milkey27cff8c2018-03-05 14:58:26 -0800560 Set<FilteredConnectPoint> ingressPoints = getHostLocations(src);
Simon Huntd2747a02015-04-30 22:41:16 -0700561
562 // FIXME: clearly, this is not enough
563 TrafficSelector selector = DefaultTrafficSelector.builder()
564 .matchEthDst(dstHost.mac()).build();
565 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
566
567 MultiPointToSinglePointIntent intent =
568 MultiPointToSinglePointIntent.builder()
569 .appId(appId)
570 .selector(selector)
571 .treatment(treatment)
Ray Milkey27cff8c2018-03-05 14:58:26 -0800572 .filteredIngressPoints(ingressPoints)
573 .filteredEgressPoint(new FilteredConnectPoint(dstHost.location()))
Simon Huntd2747a02015-04-30 22:41:16 -0700574 .build();
575
Simon Hunt1911fe42017-05-02 18:25:58 -0700576 services.intent().submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700577 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
578 traffic.monitor(intent);
579 }
Simon Huntd2747a02015-04-30 22:41:16 -0700580 }
581 }
582
Deepa Vaddireddy63340922017-01-19 08:15:31 +0530583 private final class RemoveIntents extends RequestHandler {
584 private RemoveIntents() {
585 super(REMOVE_INTENTS);
586 }
587
588
589 @Override
590 public void process(ObjectNode payload) {
591 IntentService intentService = get(IntentService.class);
592 for (Intent intent : intentService.getIntents()) {
593 if (intentService.getIntentState(intent.key()) == IntentState.WITHDRAWN) {
594 intentService.purge(intent);
595 }
596 }
597
598 }
599 }
600
Simon Hunta17fa672015-08-19 18:42:22 -0700601 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700602
Simon Hunt21281fd2017-03-30 22:28:28 -0700603 private final class ReqAllTraffic extends RequestHandler {
604 private ReqAllTraffic() {
605 super(REQ_ALL_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700606 }
607
608 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800609 public void process(ObjectNode payload) {
Simon Hunt21281fd2017-03-30 22:28:28 -0700610 String trafficType = string(payload, TRAFFIC_TYPE, FLOW_STATS_BYTES);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700611
Simon Hunt21281fd2017-03-30 22:28:28 -0700612 switch (trafficType) {
613 case FLOW_STATS_BYTES:
614 traffic.monitor(Mode.ALL_FLOW_TRAFFIC_BYTES);
615 break;
616 case PORT_STATS_BIT_SEC:
617 traffic.monitor(Mode.ALL_PORT_TRAFFIC_BIT_PS);
618 break;
619 case PORT_STATS_PKT_SEC:
620 traffic.monitor(Mode.ALL_PORT_TRAFFIC_PKT_PS);
621 break;
622 default:
623 break;
624 }
Simon Huntd2747a02015-04-30 22:41:16 -0700625 }
626 }
627
Thomas Vachuska2b4de872021-03-30 16:31:34 -0700628 private final class ReqCustomTraffic extends RequestHandler {
629 private ReqCustomTraffic() {
630 super(REQ_CUSTOM_TRAFFIC);
631 }
632
633 @Override
634 public void process(ObjectNode payload) {
635 traffic.monitor((int) number(payload, "index"));
636 }
637 }
638
Simon Hunt1911fe42017-05-02 18:25:58 -0700639 private NodeSelection makeNodeSelection(ObjectNode payload) {
640 return new NodeSelection(payload, services.device(), services.host(),
641 services.link());
642 }
643
644
Simon Huntd2747a02015-04-30 22:41:16 -0700645 private final class ReqDevLinkFlows extends RequestHandler {
646 private ReqDevLinkFlows() {
647 super(REQ_DEV_LINK_FLOWS);
648 }
649
650 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800651 public void process(ObjectNode payload) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700652 traffic.monitor(Mode.DEV_LINK_FLOWS, makeNodeSelection(payload));
Simon Hunta17fa672015-08-19 18:42:22 -0700653 }
654 }
655
656 private final class ReqRelatedIntents extends RequestHandler {
657 private ReqRelatedIntents() {
658 super(REQ_RELATED_INTENTS);
659 }
660
661 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800662 public void process(ObjectNode payload) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700663 traffic.monitor(Mode.RELATED_INTENTS, makeNodeSelection(payload));
Simon Hunta17fa672015-08-19 18:42:22 -0700664 }
665 }
666
667 private final class ReqNextIntent extends RequestHandler {
668 private ReqNextIntent() {
669 super(REQ_NEXT_INTENT);
670 }
671
672 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800673 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700674 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700675 }
676 }
677
678 private final class ReqPrevIntent extends RequestHandler {
679 private ReqPrevIntent() {
680 super(REQ_PREV_INTENT);
681 }
682
683 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800684 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700685 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700686 }
687 }
688
689 private final class ReqSelectedIntentTraffic extends RequestHandler {
690 private ReqSelectedIntentTraffic() {
691 super(REQ_SEL_INTENT_TRAFFIC);
692 }
693
694 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800695 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700696 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700697 }
698 }
699
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700700 private final class SelIntent extends RequestHandler {
701 private SelIntent() {
702 super(SEL_INTENT);
703 }
704
705 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800706 public void process(ObjectNode payload) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530707 Intent intent = findIntentByPayload(payload);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700708 if (intent == null) {
Viswanath KSP0f297702016-08-13 18:02:43 +0530709 log.warn("Unable to find intent from payload {}", payload);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700710 } else {
Viswanath KSP0f297702016-08-13 18:02:43 +0530711 log.debug("starting to monitor intent {}", intent.key());
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700712 traffic.monitor(intent);
713 }
714 }
715 }
716
Andrea Campanella732ea832017-02-06 09:25:59 -0800717 private final class SelProtectedIntent extends RequestHandler {
718 private SelProtectedIntent() {
719 super(SEL_PROTECTED_INTENT);
720 }
721
722 @Override
723 public void process(ObjectNode payload) {
724 Intent intent = findIntentByPayload(payload);
725 if (intent == null) {
726 log.warn("Unable to find protected intent from payload {}", payload);
727 } else {
728 log.debug("starting to monitor protected intent {}", intent.key());
729 protectedIntentMonitor.monitor(intent);
730 }
731 }
732 }
733
Simon Huntd2747a02015-04-30 22:41:16 -0700734 private final class CancelTraffic extends RequestHandler {
735 private CancelTraffic() {
736 super(CANCEL_TRAFFIC);
737 }
738
739 @Override
Simon Hunt8a0429a2017-01-06 16:52:47 -0800740 public void process(ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700741 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700742 }
743 }
744
Andrea Campanella732ea832017-02-06 09:25:59 -0800745 private final class CancelProtectedIntentHighlight extends RequestHandler {
746 private CancelProtectedIntentHighlight() {
747 super(CANCEL_PROTECTED_INTENT_HIGHLIGHT);
748 }
749
750 @Override
751 public void process(ObjectNode payload) {
752 protectedIntentMonitor.stopMonitoring();
753 }
754 }
755
Simon Huntd2747a02015-04-30 22:41:16 -0700756 //=======================================================================
757
Simon Hunta17fa672015-08-19 18:42:22 -0700758 // Converts highlights to JSON format and sends the message to the client
Sean Condonadeb7162019-04-13 20:56:14 +0100759 @Override
760 public void sendHighlights(Highlights highlights) {
Simon Hunt52560662015-08-27 22:46:44 -0700761 sendMessage(highlightsMessage(highlights));
Thomas Vachuska329af532015-03-10 02:08:33 -0700762 }
763
Simon Huntd2747a02015-04-30 22:41:16 -0700764 // Subscribes for summary messages.
Simon Hunt8a0429a2017-01-06 16:52:47 -0800765 private synchronized void requestSummary() {
766 PropertyPanel pp = summmaryMessage();
Simon Hunt0af1ec32015-07-24 12:17:55 -0700767 overlayCache.currentOverlay().modifySummary(pp);
Simon Hunt8a0429a2017-01-06 16:52:47 -0800768 sendMessage(envelope(SHOW_SUMMARY, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700769 }
770
Simon Huntd2747a02015-04-30 22:41:16 -0700771
Thomas Vachuska329af532015-03-10 02:08:33 -0700772 private void cancelAllRequests() {
773 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700774 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700775 }
776
777 // Sends all controller nodes to the client as node-added messages.
778 private void sendAllInstances(String messageType) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700779 List<ControllerNode> nodes = new ArrayList<>(services.cluster().getNodes());
Simon Hunt8a0429a2017-01-06 16:52:47 -0800780 nodes.sort(NODE_COMPARATOR);
Thomas Vachuska329af532015-03-10 02:08:33 -0700781 for (ControllerNode node : nodes) {
782 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
Andrea Campanella732ea832017-02-06 09:25:59 -0800783 messageType));
Thomas Vachuska329af532015-03-10 02:08:33 -0700784 }
785 }
786
787 // Sends all devices to the client as device-added messages.
788 private void sendAllDevices() {
789 // Send optical first, others later for layered rendering
Simon Hunt1911fe42017-05-02 18:25:58 -0700790 for (Device device : services.device().getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200791 if ((device.type() == Device.Type.ROADM) ||
Andrea Campanella1c24fb92018-12-20 16:43:59 +0100792 (device.type() == Device.Type.OTN) ||
793 (device.type() == Device.Type.OLS) ||
794 (device.type() == Device.Type.TERMINAL_DEVICE)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700795 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
796 }
797 }
Simon Hunt1911fe42017-05-02 18:25:58 -0700798 for (Device device : services.device().getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200799 if ((device.type() != Device.Type.ROADM) &&
Andrea Campanellafa0f6cc2018-12-18 15:17:53 +0100800 (device.type() != Device.Type.OTN) && (device.type() != Device.Type.OLS) &&
Andrea Campanella1c24fb92018-12-20 16:43:59 +0100801 (device.type() != Device.Type.TERMINAL_DEVICE) && (device.type() != Device.Type.CONTROLLER)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700802 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
803 }
804 }
805 }
806
807 // Sends all links to the client as link-added messages.
808 private void sendAllLinks() {
809 // Send optical first, others later for layered rendering
Simon Hunt1911fe42017-05-02 18:25:58 -0700810 for (Link link : services.link().getLinks()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700811 if (link.type() == Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700812 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700813 }
814 }
Simon Hunt1911fe42017-05-02 18:25:58 -0700815 for (Link link : services.link().getLinks()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700816 if (link.type() != Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700817 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700818 }
819 }
820 }
821
Simon Hunt5c1a9382016-06-01 19:35:35 -0700822 // Temporary mechanism to support topology overlays adding their own
823 // properties to the link events.
824 private ObjectNode composeLinkMessage(LinkEvent event) {
825 // start with base message
826 ObjectNode msg = linkMessage(event);
827 Map<String, String> additional =
828 overlayCache.currentOverlay().additionalLinkData(event);
829
830 if (additional != null) {
831 // attach additional key-value pairs as extra data structure
832 ObjectNode payload = (ObjectNode) msg.get(PAYLOAD);
833 payload.set(EXTRA, createExtra(additional));
834 }
835 return msg;
836 }
837
838 private ObjectNode createExtra(Map<String, String> additional) {
839 ObjectNode extra = objectNode();
840 for (Map.Entry<String, String> entry : additional.entrySet()) {
841 extra.put(entry.getKey(), entry.getValue());
842 }
843 return extra;
844 }
845
Thomas Vachuska329af532015-03-10 02:08:33 -0700846 // Sends all hosts to the client as host-added messages.
847 private void sendAllHosts() {
Simon Hunt1911fe42017-05-02 18:25:58 -0700848 for (Host host : services.host().getHosts()) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700849 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
850 }
851 }
852
Ray Milkey27cff8c2018-03-05 14:58:26 -0800853 private Set<FilteredConnectPoint> getHostLocations(Set<HostId> hostIds) {
854 Set<FilteredConnectPoint> points = new HashSet<>();
Thomas Vachuska329af532015-03-10 02:08:33 -0700855 for (HostId hostId : hostIds) {
Ray Milkey27cff8c2018-03-05 14:58:26 -0800856 points.add(new FilteredConnectPoint(getHostLocation(hostId)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700857 }
858 return points;
859 }
860
861 private HostLocation getHostLocation(HostId hostId) {
Simon Hunt1911fe42017-05-02 18:25:58 -0700862 return services.host().getHost(hostId).location();
Thomas Vachuska329af532015-03-10 02:08:33 -0700863 }
864
865 // Produces a list of host ids from the specified JSON array.
866 private Set<HostId> getHostIds(ArrayNode ids) {
867 Set<HostId> hostIds = new HashSet<>();
868 for (JsonNode id : ids) {
869 hostIds.add(hostId(id.asText()));
870 }
871 return hostIds;
872 }
873
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700874 private void sendTopoStartDone() {
875 sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode()));
876 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700877
Simon Huntd2747a02015-04-30 22:41:16 -0700878 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700879 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700880 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700881 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700882 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700883 }
884
885 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700886 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700887 summaryTask.cancel();
888 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700889 }
Simon Huntd2747a02015-04-30 22:41:16 -0700890 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700891 }
892
Thomas Vachuska329af532015-03-10 02:08:33 -0700893
894 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700895 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700896 listenersRemoved = false;
Simon Hunt1911fe42017-05-02 18:25:58 -0700897 services.cluster().addListener(clusterListener);
898 services.mastership().addListener(mastershipListener);
899 services.device().addListener(deviceListener);
900 services.link().addListener(linkListener);
901 services.host().addListener(hostListener);
902 services.intent().addListener(intentListener);
903 services.flow().addListener(flowListener);
Thomas Vachuska329af532015-03-10 02:08:33 -0700904 }
905
906 // Removes all internal listeners.
907 private synchronized void removeListeners() {
908 if (!listenersRemoved) {
909 listenersRemoved = true;
Simon Hunt1911fe42017-05-02 18:25:58 -0700910 services.cluster().removeListener(clusterListener);
911 services.mastership().removeListener(mastershipListener);
912 services.device().removeListener(deviceListener);
913 services.link().removeListener(linkListener);
914 services.host().removeListener(hostListener);
915 services.intent().removeListener(intentListener);
916 services.flow().removeListener(flowListener);
Thomas Vachuska329af532015-03-10 02:08:33 -0700917 }
918 }
919
920 // Cluster event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700921 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
922 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700923 private class InternalClusterListener implements ClusterEventListener {
924 @Override
925 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700926 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700927 }
928 }
929
930 // Mastership change listener
Simon Hunt7092cc42016-04-06 18:40:17 -0700931 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
932 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700933 private class InternalMastershipListener implements MastershipListener {
934 @Override
935 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700936 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700937 sendAllInstances(UPDATE_INSTANCE);
Simon Hunt1911fe42017-05-02 18:25:58 -0700938 Device device = services.device().getDevice(event.subject());
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700939 if (device != null) {
940 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
941 }
942 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700943 }
944 }
945
946 // Device event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700947 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
948 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700949 private class InternalDeviceListener implements DeviceListener {
950 @Override
951 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700952 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700953 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800954 msgSender.execute(traffic::pokeIntent);
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700955 eventAccummulator.add(event);
956 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700957 }
958 }
959
960 // Link event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700961 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
962 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700963 private class InternalLinkListener implements LinkListener {
964 @Override
965 public void event(LinkEvent event) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700966 msgSender.execute(() -> sendMessage(composeLinkMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800967 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700968 eventAccummulator.add(event);
969 }
970 }
971
972 // Host event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700973 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
974 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700975 private class InternalHostListener implements HostListener {
976 @Override
977 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700978 msgSender.execute(() -> sendMessage(hostMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800979 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700980 eventAccummulator.add(event);
981 }
982 }
983
984 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700985 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
986 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700987 private class InternalIntentListener implements IntentListener {
988 @Override
989 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700990 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700991 eventAccummulator.add(event);
992 }
993 }
994
995 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700996 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
997 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700998 private class InternalFlowListener implements FlowRuleListener {
999 @Override
1000 public void event(FlowRuleEvent event) {
1001 eventAccummulator.add(event);
1002 }
1003 }
1004
Simon Huntd2747a02015-04-30 22:41:16 -07001005
Simon Hunta17fa672015-08-19 18:42:22 -07001006 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -07001007
1008 // Periodic update of the summary information
1009 private class SummaryMonitor extends TimerTask {
1010 @Override
1011 public void run() {
1012 try {
Simon Huntd2747a02015-04-30 22:41:16 -07001013 if (summaryRunning) {
Simon Hunt8a0429a2017-01-06 16:52:47 -08001014 msgSender.execute(() -> requestSummary());
Thomas Vachuska329af532015-03-10 02:08:33 -07001015 }
1016 } catch (Exception e) {
1017 log.warn("Unable to handle summary request due to {}", e.getMessage());
1018 log.warn("Boom!", e);
1019 }
1020 }
1021 }
1022
1023 // Accumulates events to drive methodic update of the summary pane.
1024 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
1025 protected InternalEventAccummulator() {
1026 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
1027 }
1028
1029 @Override
1030 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -07001031 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -07001032 long now = System.currentTimeMillis();
1033 String me = this.toString();
1034 String miniMe = me.replaceAll("^.*@", "me@");
1035 log.debug("Time: {}; this: {}, processing items ({} events)",
Andrea Campanella732ea832017-02-06 09:25:59 -08001036 now, miniMe, items.size());
Simon Hunt8d22c4b2015-08-06 16:24:43 -07001037 // End-of-Debugging
1038
Thomas Vachuska329af532015-03-10 02:08:33 -07001039 try {
Simon Huntd2747a02015-04-30 22:41:16 -07001040 if (summaryRunning) {
Simon Hunt8a0429a2017-01-06 16:52:47 -08001041 msgSender.execute(() -> requestSummary());
Thomas Vachuska329af532015-03-10 02:08:33 -07001042 }
1043 } catch (Exception e) {
1044 log.warn("Unable to handle summary request due to {}", e.getMessage());
1045 log.debug("Boom!", e);
1046 }
1047 }
1048 }
1049}