blob: 71c017dc5f3ed67580829f3558e6512469b1709c [file] [log] [blame]
Thomas Vachuska329af532015-03-10 02:08:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska329af532015-03-10 02:08:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.ui.impl;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.ImmutableSet;
22import org.onlab.osgi.ServiceDirectory;
23import org.onlab.util.AbstractAccumulator;
24import org.onlab.util.Accumulator;
25import org.onosproject.cluster.ClusterEvent;
26import org.onosproject.cluster.ClusterEventListener;
27import org.onosproject.cluster.ControllerNode;
28import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070030import org.onosproject.core.DefaultApplicationId;
Thomas Vachuska329af532015-03-10 02:08:33 -070031import org.onosproject.event.Event;
32import org.onosproject.mastership.MastershipAdminService;
33import org.onosproject.mastership.MastershipEvent;
34import org.onosproject.mastership.MastershipListener;
35import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.Device;
Simon Huntde99e0b2015-10-23 18:54:06 -070037import org.onosproject.net.DeviceId;
Thomas Vachuska329af532015-03-10 02:08:33 -070038import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.HostLocation;
41import org.onosproject.net.Link;
42import org.onosproject.net.device.DeviceEvent;
43import org.onosproject.net.device.DeviceListener;
44import org.onosproject.net.flow.DefaultTrafficSelector;
45import org.onosproject.net.flow.DefaultTrafficTreatment;
46import org.onosproject.net.flow.FlowRuleEvent;
47import org.onosproject.net.flow.FlowRuleListener;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
50import org.onosproject.net.host.HostEvent;
51import org.onosproject.net.host.HostListener;
52import org.onosproject.net.intent.HostToHostIntent;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070053import org.onosproject.net.intent.Intent;
Thomas Vachuska329af532015-03-10 02:08:33 -070054import org.onosproject.net.intent.IntentEvent;
55import org.onosproject.net.intent.IntentListener;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070056import org.onosproject.net.intent.Key;
Thomas Vachuska329af532015-03-10 02:08:33 -070057import org.onosproject.net.intent.MultiPointToSinglePointIntent;
58import org.onosproject.net.link.LinkEvent;
59import org.onosproject.net.link.LinkListener;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070060import org.onosproject.ui.JsonUtils;
Simon Huntd2747a02015-04-30 22:41:16 -070061import org.onosproject.ui.RequestHandler;
Thomas Vachuska329af532015-03-10 02:08:33 -070062import org.onosproject.ui.UiConnection;
Simon Hunt4fc86852015-08-20 17:57:52 -070063import org.onosproject.ui.impl.TrafficMonitor.Mode;
Simon Hunta17fa672015-08-19 18:42:22 -070064import org.onosproject.ui.topo.Highlights;
Simon Huntd3ceffa2015-08-25 12:44:35 -070065import org.onosproject.ui.topo.NodeSelection;
Simon Hunt0af1ec32015-07-24 12:17:55 -070066import org.onosproject.ui.topo.PropertyPanel;
Thomas Vachuska329af532015-03-10 02:08:33 -070067
68import java.util.ArrayList;
Simon Huntd2747a02015-04-30 22:41:16 -070069import java.util.Collection;
Thomas Vachuska329af532015-03-10 02:08:33 -070070import java.util.Collections;
71import java.util.Comparator;
72import java.util.HashSet;
73import java.util.List;
Simon Hunt5c1a9382016-06-01 19:35:35 -070074import java.util.Map;
Thomas Vachuska329af532015-03-10 02:08:33 -070075import java.util.Set;
76import java.util.Timer;
77import java.util.TimerTask;
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070078import java.util.concurrent.ExecutorService;
Thomas Vachuska329af532015-03-10 02:08:33 -070079
Thomas Vachuska52c98bd2015-05-27 20:54:02 -070080import static java.util.concurrent.Executors.newSingleThreadExecutor;
81import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska329af532015-03-10 02:08:33 -070082import static org.onosproject.cluster.ClusterEvent.Type.INSTANCE_ADDED;
83import static org.onosproject.net.DeviceId.deviceId;
84import static org.onosproject.net.HostId.hostId;
Simon Hunt4a6b54b2015-10-27 22:08:25 -070085import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_ADDED;
86import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_UPDATED;
87import static org.onosproject.net.device.DeviceEvent.Type.PORT_STATS_UPDATED;
Thomas Vachuska329af532015-03-10 02:08:33 -070088import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED;
89import static org.onosproject.net.link.LinkEvent.Type.LINK_ADDED;
Simon Huntd3ceffa2015-08-25 12:44:35 -070090import static org.onosproject.ui.JsonUtils.envelope;
Simon Hunt52560662015-08-27 22:46:44 -070091import static org.onosproject.ui.topo.TopoJson.highlightsMessage;
92import static org.onosproject.ui.topo.TopoJson.json;
Thomas Vachuska329af532015-03-10 02:08:33 -070093
94/**
95 * Web socket capable of interacting with the GUI topology view.
96 */
97public class TopologyViewMessageHandler extends TopologyViewMessageHandlerBase {
98
Simon Huntb745ca62015-07-28 15:37:11 -070099 // incoming event types
Simon Huntd2747a02015-04-30 22:41:16 -0700100 private static final String REQ_DETAILS = "requestDetails";
101 private static final String UPDATE_META = "updateMeta";
102 private static final String ADD_HOST_INTENT = "addHostIntent";
103 private static final String ADD_MULTI_SRC_INTENT = "addMultiSourceIntent";
104 private static final String REQ_RELATED_INTENTS = "requestRelatedIntents";
105 private static final String REQ_NEXT_INTENT = "requestNextRelatedIntent";
106 private static final String REQ_PREV_INTENT = "requestPrevRelatedIntent";
107 private static final String REQ_SEL_INTENT_TRAFFIC = "requestSelectedIntentTraffic";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700108 private static final String SEL_INTENT = "selectIntent";
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700109 private static final String REQ_ALL_FLOW_TRAFFIC = "requestAllFlowTraffic";
110 private static final String REQ_ALL_PORT_TRAFFIC = "requestAllPortTraffic";
Simon Huntd2747a02015-04-30 22:41:16 -0700111 private static final String REQ_DEV_LINK_FLOWS = "requestDeviceLinkFlows";
112 private static final String CANCEL_TRAFFIC = "cancelTraffic";
113 private static final String REQ_SUMMARY = "requestSummary";
114 private static final String CANCEL_SUMMARY = "cancelSummary";
115 private static final String EQ_MASTERS = "equalizeMasters";
116 private static final String SPRITE_LIST_REQ = "spriteListRequest";
117 private static final String SPRITE_DATA_REQ = "spriteDataRequest";
118 private static final String TOPO_START = "topoStart";
Simon Hunt732bb2e2015-05-13 18:32:16 -0700119 private static final String TOPO_HEARTBEAT = "topoHeartbeat";
Simon Hunte05cae42015-07-23 17:35:24 -0700120 private static final String TOPO_SELECT_OVERLAY = "topoSelectOverlay";
Simon Huntd2747a02015-04-30 22:41:16 -0700121 private static final String TOPO_STOP = "topoStop";
122
Simon Huntb745ca62015-07-28 15:37:11 -0700123 // outgoing event types
124 private static final String SHOW_SUMMARY = "showSummary";
125 private static final String SHOW_DETAILS = "showDetails";
126 private static final String SPRITE_LIST_RESPONSE = "spriteListResponse";
127 private static final String SPRITE_DATA_RESPONSE = "spriteDataResponse";
128 private static final String UPDATE_INSTANCE = "updateInstance";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700129 private static final String TOPO_START_DONE = "topoStartDone";
Simon Huntb745ca62015-07-28 15:37:11 -0700130
131 // fields
Simon Hunt5c1a9382016-06-01 19:35:35 -0700132 private static final String PAYLOAD = "payload";
133 private static final String EXTRA = "extra";
Simon Huntb745ca62015-07-28 15:37:11 -0700134 private static final String ID = "id";
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700135 private static final String KEY = "key";
136 private static final String APP_ID = "appId";
137 private static final String APP_NAME = "appName";
Simon Huntb745ca62015-07-28 15:37:11 -0700138 private static final String DEVICE = "device";
139 private static final String HOST = "host";
140 private static final String CLASS = "class";
141 private static final String UNKNOWN = "unknown";
142 private static final String ONE = "one";
143 private static final String TWO = "two";
144 private static final String SRC = "src";
145 private static final String DST = "dst";
146 private static final String DATA = "data";
147 private static final String NAME = "name";
148 private static final String NAMES = "names";
149 private static final String ACTIVATE = "activate";
150 private static final String DEACTIVATE = "deactivate";
Simon Huntb745ca62015-07-28 15:37:11 -0700151
Simon Huntd2747a02015-04-30 22:41:16 -0700152
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700153 private static final String MY_APP_ID = "org.onosproject.gui";
Thomas Vachuska329af532015-03-10 02:08:33 -0700154
Simon Hunta17fa672015-08-19 18:42:22 -0700155 private static final long TRAFFIC_PERIOD = 5000;
156 private static final long SUMMARY_PERIOD = 30000;
Thomas Vachuska329af532015-03-10 02:08:33 -0700157
158 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
Thomas Vachuskac0fe09a2015-05-21 12:56:22 -0700159 (o1, o2) -> o1.id().toString().compareTo(o2.id().toString());
Thomas Vachuska329af532015-03-10 02:08:33 -0700160
161
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700162 private final Timer timer = new Timer("onos-topology-view");
Thomas Vachuska329af532015-03-10 02:08:33 -0700163
164 private static final int MAX_EVENTS = 1000;
165 private static final int MAX_BATCH_MS = 5000;
166 private static final int MAX_IDLE_MS = 1000;
167
168 private ApplicationId appId;
169
170 private final ClusterEventListener clusterListener = new InternalClusterListener();
171 private final MastershipListener mastershipListener = new InternalMastershipListener();
172 private final DeviceListener deviceListener = new InternalDeviceListener();
173 private final LinkListener linkListener = new InternalLinkListener();
174 private final HostListener hostListener = new InternalHostListener();
175 private final IntentListener intentListener = new InternalIntentListener();
176 private final FlowRuleListener flowListener = new InternalFlowListener();
177
178 private final Accumulator<Event> eventAccummulator = new InternalEventAccummulator();
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700179 private final ExecutorService msgSender =
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700180 newSingleThreadExecutor(groupedThreads("onos/gui", "msg-sender", log));
Thomas Vachuska329af532015-03-10 02:08:33 -0700181
Simon Hunta17fa672015-08-19 18:42:22 -0700182 private TopoOverlayCache overlayCache;
Simon Hunt4fc86852015-08-20 17:57:52 -0700183 private TrafficMonitor traffic;
Thomas Vachuska329af532015-03-10 02:08:33 -0700184
Simon Huntd2747a02015-04-30 22:41:16 -0700185 private TimerTask summaryTask = null;
186 private boolean summaryRunning = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700187
Simon Huntd5b96732016-07-08 13:22:27 -0700188 private volatile boolean listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700189
Thomas Vachuska329af532015-03-10 02:08:33 -0700190
191 @Override
192 public void init(UiConnection connection, ServiceDirectory directory) {
193 super.init(connection, directory);
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700194 appId = directory.get(CoreService.class).registerApplication(MY_APP_ID);
Simon Hunt4fc86852015-08-20 17:57:52 -0700195 traffic = new TrafficMonitor(TRAFFIC_PERIOD, servicesBundle, this);
Thomas Vachuska329af532015-03-10 02:08:33 -0700196 }
197
198 @Override
199 public void destroy() {
200 cancelAllRequests();
Thomas Vachuska2bb48632015-04-28 14:40:42 -0700201 removeListeners();
Thomas Vachuska329af532015-03-10 02:08:33 -0700202 super.destroy();
203 }
204
Thomas Vachuska329af532015-03-10 02:08:33 -0700205 @Override
Simon Huntda580882015-05-12 20:58:18 -0700206 protected Collection<RequestHandler> createRequestHandlers() {
Simon Huntd2747a02015-04-30 22:41:16 -0700207 return ImmutableSet.of(
208 new TopoStart(),
Simon Hunt732bb2e2015-05-13 18:32:16 -0700209 new TopoHeartbeat(),
Simon Hunte05cae42015-07-23 17:35:24 -0700210 new TopoSelectOverlay(),
Simon Huntd2747a02015-04-30 22:41:16 -0700211 new TopoStop(),
212 new ReqSummary(),
213 new CancelSummary(),
214 new SpriteListReq(),
215 new SpriteDataReq(),
216 new RequestDetails(),
217 new UpdateMeta(),
218 new EqMasters(),
Thomas Vachuska329af532015-03-10 02:08:33 -0700219
Simon Huntd2747a02015-04-30 22:41:16 -0700220 // TODO: migrate traffic related to separate app
221 new AddHostIntent(),
222 new AddMultiSourceIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700223
224 new ReqAllFlowTraffic(),
225 new ReqAllPortTraffic(),
226 new ReqDevLinkFlows(),
Simon Huntd2747a02015-04-30 22:41:16 -0700227 new ReqRelatedIntents(),
228 new ReqNextIntent(),
229 new ReqPrevIntent(),
230 new ReqSelectedIntentTraffic(),
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700231 new SelIntent(),
Simon Hunta17fa672015-08-19 18:42:22 -0700232
Simon Huntd2747a02015-04-30 22:41:16 -0700233 new CancelTraffic()
234 );
235 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700236
Simon Hunte05cae42015-07-23 17:35:24 -0700237 /**
238 * Injects the topology overlay cache.
239 *
240 * @param overlayCache injected cache
241 */
242 void setOverlayCache(TopoOverlayCache overlayCache) {
243 this.overlayCache = overlayCache;
244 }
245
Simon Huntd2747a02015-04-30 22:41:16 -0700246 // ==================================================================
Thomas Vachuska329af532015-03-10 02:08:33 -0700247
Simon Huntd2747a02015-04-30 22:41:16 -0700248 private final class TopoStart extends RequestHandler {
249 private TopoStart() {
250 super(TOPO_START);
251 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700252
Simon Huntd2747a02015-04-30 22:41:16 -0700253 @Override
254 public void process(long sid, ObjectNode payload) {
255 addListeners();
256 sendAllInstances(null);
257 sendAllDevices();
258 sendAllLinks();
259 sendAllHosts();
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700260 sendTopoStartDone();
Thomas Vachuska329af532015-03-10 02:08:33 -0700261 }
262 }
263
Simon Hunt732bb2e2015-05-13 18:32:16 -0700264 private final class TopoHeartbeat extends RequestHandler {
265 private TopoHeartbeat() {
266 super(TOPO_HEARTBEAT);
267 }
268
269 @Override
270 public void process(long sid, ObjectNode payload) {
271 // place holder for now
272 }
273 }
274
Simon Hunte05cae42015-07-23 17:35:24 -0700275 private final class TopoSelectOverlay extends RequestHandler {
276 private TopoSelectOverlay() {
277 super(TOPO_SELECT_OVERLAY);
278 }
279
280 @Override
281 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700282 String deact = string(payload, DEACTIVATE);
283 String act = string(payload, ACTIVATE);
Simon Hunte05cae42015-07-23 17:35:24 -0700284 overlayCache.switchOverlay(deact, act);
285 }
286 }
287
Simon Huntd2747a02015-04-30 22:41:16 -0700288 private final class TopoStop extends RequestHandler {
289 private TopoStop() {
290 super(TOPO_STOP);
291 }
292
293 @Override
294 public void process(long sid, ObjectNode payload) {
Simon Hunt1ad59272015-11-10 15:23:21 -0800295 removeListeners();
Simon Huntd2747a02015-04-30 22:41:16 -0700296 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700297 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700298 }
299 }
300
301 private final class ReqSummary extends RequestHandler {
302 private ReqSummary() {
303 super(REQ_SUMMARY);
304 }
305
306 @Override
307 public void process(long sid, ObjectNode payload) {
308 requestSummary(sid);
309 startSummaryMonitoring();
310 }
311 }
312
313 private final class CancelSummary extends RequestHandler {
314 private CancelSummary() {
315 super(CANCEL_SUMMARY);
316 }
317
318 @Override
319 public void process(long sid, ObjectNode payload) {
320 stopSummaryMonitoring();
321 }
322 }
323
324 private final class SpriteListReq extends RequestHandler {
325 private SpriteListReq() {
326 super(SPRITE_LIST_REQ);
327 }
328
329 @Override
330 public void process(long sid, ObjectNode payload) {
Simon Huntda580882015-05-12 20:58:18 -0700331 ObjectNode root = objectNode();
332 ArrayNode names = arrayNode();
Simon Huntd2747a02015-04-30 22:41:16 -0700333 get(SpriteService.class).getNames().forEach(names::add);
Simon Huntb745ca62015-07-28 15:37:11 -0700334 root.set(NAMES, names);
335 sendMessage(SPRITE_LIST_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700336 }
337 }
338
339 private final class SpriteDataReq extends RequestHandler {
340 private SpriteDataReq() {
341 super(SPRITE_DATA_REQ);
342 }
343
344 @Override
345 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700346 String name = string(payload, NAME);
Simon Huntda580882015-05-12 20:58:18 -0700347 ObjectNode root = objectNode();
Simon Huntb745ca62015-07-28 15:37:11 -0700348 root.set(DATA, get(SpriteService.class).get(name));
349 sendMessage(SPRITE_DATA_RESPONSE, sid, root);
Simon Huntd2747a02015-04-30 22:41:16 -0700350 }
351 }
352
353 private final class RequestDetails extends RequestHandler {
354 private RequestDetails() {
355 super(REQ_DETAILS);
356 }
357
358 @Override
359 public void process(long sid, ObjectNode payload) {
Simon Huntb745ca62015-07-28 15:37:11 -0700360 String type = string(payload, CLASS, UNKNOWN);
361 String id = string(payload, ID);
362 PropertyPanel pp = null;
Simon Huntd2747a02015-04-30 22:41:16 -0700363
Simon Huntb745ca62015-07-28 15:37:11 -0700364 if (type.equals(DEVICE)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700365 DeviceId did = deviceId(id);
366 pp = deviceDetails(did, sid);
367 overlayCache.currentOverlay().modifyDeviceDetails(pp, did);
Simon Huntb745ca62015-07-28 15:37:11 -0700368 } else if (type.equals(HOST)) {
Simon Huntde99e0b2015-10-23 18:54:06 -0700369 HostId hid = hostId(id);
370 pp = hostDetails(hid, sid);
371 overlayCache.currentOverlay().modifyHostDetails(pp, hid);
Simon Huntd2747a02015-04-30 22:41:16 -0700372 }
Simon Huntb745ca62015-07-28 15:37:11 -0700373
Simon Huntd3ceffa2015-08-25 12:44:35 -0700374 sendMessage(envelope(SHOW_DETAILS, sid, json(pp)));
Simon Huntd2747a02015-04-30 22:41:16 -0700375 }
376 }
377
378 private final class UpdateMeta extends RequestHandler {
379 private UpdateMeta() {
380 super(UPDATE_META);
381 }
382
383 @Override
384 public void process(long sid, ObjectNode payload) {
385 updateMetaUi(payload);
386 }
387 }
388
389 private final class EqMasters extends RequestHandler {
390 private EqMasters() {
391 super(EQ_MASTERS);
392 }
393
394 @Override
395 public void process(long sid, ObjectNode payload) {
396 directory.get(MastershipAdminService.class).balanceRoles();
397 }
398 }
399
Simon Hunta17fa672015-08-19 18:42:22 -0700400
401 // ========= -----------------------------------------------------------------
402
Simon Huntd2747a02015-04-30 22:41:16 -0700403 // === TODO: move traffic related classes to traffic app
404
405 private final class AddHostIntent extends RequestHandler {
406 private AddHostIntent() {
407 super(ADD_HOST_INTENT);
408 }
409
410 @Override
411 public void process(long sid, ObjectNode payload) {
412 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700413 HostId one = hostId(string(payload, ONE));
414 HostId two = hostId(string(payload, TWO));
Simon Huntd2747a02015-04-30 22:41:16 -0700415
416 HostToHostIntent intent = HostToHostIntent.builder()
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700417 .appId(appId)
418 .one(one)
419 .two(two)
420 .build();
Simon Huntd2747a02015-04-30 22:41:16 -0700421
422 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700423 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
424 traffic.monitor(intent);
425 }
Simon Huntd2747a02015-04-30 22:41:16 -0700426 }
427 }
428
429 private final class AddMultiSourceIntent extends RequestHandler {
430 private AddMultiSourceIntent() {
431 super(ADD_MULTI_SRC_INTENT);
432 }
433
434 @Override
435 public void process(long sid, ObjectNode payload) {
436 // TODO: add protection against device ids and non-existent hosts.
Simon Huntb745ca62015-07-28 15:37:11 -0700437 Set<HostId> src = getHostIds((ArrayNode) payload.path(SRC));
438 HostId dst = hostId(string(payload, DST));
Simon Huntd2747a02015-04-30 22:41:16 -0700439 Host dstHost = hostService.getHost(dst);
440
441 Set<ConnectPoint> ingressPoints = getHostLocations(src);
442
443 // FIXME: clearly, this is not enough
444 TrafficSelector selector = DefaultTrafficSelector.builder()
445 .matchEthDst(dstHost.mac()).build();
446 TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment();
447
448 MultiPointToSinglePointIntent intent =
449 MultiPointToSinglePointIntent.builder()
450 .appId(appId)
451 .selector(selector)
452 .treatment(treatment)
453 .ingressPoints(ingressPoints)
454 .egressPoint(dstHost.location())
455 .build();
456
457 intentService.submit(intent);
Simon Huntd2862c32015-08-24 17:41:51 -0700458 if (overlayCache.isActive(TrafficOverlay.TRAFFIC_ID)) {
459 traffic.monitor(intent);
460 }
Simon Huntd2747a02015-04-30 22:41:16 -0700461 }
462 }
463
Simon Hunta17fa672015-08-19 18:42:22 -0700464 // ========= -----------------------------------------------------------------
Simon Huntd2747a02015-04-30 22:41:16 -0700465
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700466 private final class ReqAllFlowTraffic extends RequestHandler {
467 private ReqAllFlowTraffic() {
468 super(REQ_ALL_FLOW_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700469 }
470
471 @Override
472 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700473 traffic.monitor(Mode.ALL_FLOW_TRAFFIC);
Thomas Vachuskaf0397b52015-05-29 13:50:17 -0700474 }
475 }
476
477 private final class ReqAllPortTraffic extends RequestHandler {
478 private ReqAllPortTraffic() {
479 super(REQ_ALL_PORT_TRAFFIC);
480 }
481
482 @Override
483 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700484 traffic.monitor(Mode.ALL_PORT_TRAFFIC);
Simon Huntd2747a02015-04-30 22:41:16 -0700485 }
486 }
487
488 private final class ReqDevLinkFlows extends RequestHandler {
489 private ReqDevLinkFlows() {
490 super(REQ_DEV_LINK_FLOWS);
491 }
492
493 @Override
494 public void process(long sid, ObjectNode payload) {
Simon Hunta17fa672015-08-19 18:42:22 -0700495 NodeSelection nodeSelection =
496 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700497 traffic.monitor(Mode.DEV_LINK_FLOWS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700498 }
499 }
500
501 private final class ReqRelatedIntents extends RequestHandler {
502 private ReqRelatedIntents() {
503 super(REQ_RELATED_INTENTS);
504 }
505
506 @Override
507 public void process(long sid, ObjectNode payload) {
508 NodeSelection nodeSelection =
509 new NodeSelection(payload, deviceService, hostService);
Simon Hunt4fc86852015-08-20 17:57:52 -0700510 traffic.monitor(Mode.RELATED_INTENTS, nodeSelection);
Simon Hunta17fa672015-08-19 18:42:22 -0700511 }
512 }
513
514 private final class ReqNextIntent extends RequestHandler {
515 private ReqNextIntent() {
516 super(REQ_NEXT_INTENT);
517 }
518
519 @Override
520 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700521 traffic.selectNextIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700522 }
523 }
524
525 private final class ReqPrevIntent extends RequestHandler {
526 private ReqPrevIntent() {
527 super(REQ_PREV_INTENT);
528 }
529
530 @Override
531 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700532 traffic.selectPreviousIntent();
Simon Hunta17fa672015-08-19 18:42:22 -0700533 }
534 }
535
536 private final class ReqSelectedIntentTraffic extends RequestHandler {
537 private ReqSelectedIntentTraffic() {
538 super(REQ_SEL_INTENT_TRAFFIC);
539 }
540
541 @Override
542 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700543 traffic.monitor(Mode.SELECTED_INTENT);
Simon Huntd2747a02015-04-30 22:41:16 -0700544 }
545 }
546
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700547 private final class SelIntent extends RequestHandler {
548 private SelIntent() {
549 super(SEL_INTENT);
550 }
551
552 @Override
553 public void process(long sid, ObjectNode payload) {
554 int appId = Integer.parseInt(string(payload, APP_ID));
555 String appName = string(payload, APP_NAME);
556 ApplicationId applicId = new DefaultApplicationId(appId, appName);
557 long intentKey = Long.decode(string(payload, KEY));
558
559 Key key = Key.of(intentKey, applicId);
560 log.debug("Attempting to select intent key={}", key);
561
562 Intent intent = intentService.getIntent(key);
563 if (intent == null) {
564 log.debug("no such intent found!");
565 } else {
566 log.debug("starting to monitor intent {}", key);
567 traffic.monitor(intent);
568 }
569 }
570 }
571
Simon Huntd2747a02015-04-30 22:41:16 -0700572 private final class CancelTraffic extends RequestHandler {
573 private CancelTraffic() {
574 super(CANCEL_TRAFFIC);
575 }
576
577 @Override
578 public void process(long sid, ObjectNode payload) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700579 traffic.stopMonitoring();
Simon Huntd2747a02015-04-30 22:41:16 -0700580 }
581 }
582
583 //=======================================================================
584
Simon Hunta17fa672015-08-19 18:42:22 -0700585 // Converts highlights to JSON format and sends the message to the client
586 protected void sendHighlights(Highlights highlights) {
Simon Hunt52560662015-08-27 22:46:44 -0700587 sendMessage(highlightsMessage(highlights));
Thomas Vachuska329af532015-03-10 02:08:33 -0700588 }
589
Simon Huntd2747a02015-04-30 22:41:16 -0700590 // Subscribes for summary messages.
591 private synchronized void requestSummary(long sid) {
Simon Hunt0af1ec32015-07-24 12:17:55 -0700592 PropertyPanel pp = summmaryMessage(sid);
593 overlayCache.currentOverlay().modifySummary(pp);
Simon Huntd3ceffa2015-08-25 12:44:35 -0700594 sendMessage(envelope(SHOW_SUMMARY, sid, json(pp)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700595 }
596
Simon Huntd2747a02015-04-30 22:41:16 -0700597
Thomas Vachuska329af532015-03-10 02:08:33 -0700598 private void cancelAllRequests() {
599 stopSummaryMonitoring();
Simon Hunt4fc86852015-08-20 17:57:52 -0700600 traffic.stopMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700601 }
602
603 // Sends all controller nodes to the client as node-added messages.
604 private void sendAllInstances(String messageType) {
605 List<ControllerNode> nodes = new ArrayList<>(clusterService.getNodes());
606 Collections.sort(nodes, NODE_COMPARATOR);
607 for (ControllerNode node : nodes) {
608 sendMessage(instanceMessage(new ClusterEvent(INSTANCE_ADDED, node),
Simon Hunt5c1a9382016-06-01 19:35:35 -0700609 messageType));
Thomas Vachuska329af532015-03-10 02:08:33 -0700610 }
611 }
612
613 // Sends all devices to the client as device-added messages.
614 private void sendAllDevices() {
615 // Send optical first, others later for layered rendering
616 for (Device device : deviceService.getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200617 if ((device.type() == Device.Type.ROADM) ||
Simon Hunt5c1a9382016-06-01 19:35:35 -0700618 (device.type() == Device.Type.OTN)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700619 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
620 }
621 }
622 for (Device device : deviceService.getDevices()) {
Rimon Ashkenazy8ebfff02016-02-01 11:56:36 +0200623 if ((device.type() != Device.Type.ROADM) &&
Simon Hunt5c1a9382016-06-01 19:35:35 -0700624 (device.type() != Device.Type.OTN)) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700625 sendMessage(deviceMessage(new DeviceEvent(DEVICE_ADDED, device)));
626 }
627 }
628 }
629
630 // Sends all links to the client as link-added messages.
631 private void sendAllLinks() {
632 // Send optical first, others later for layered rendering
633 for (Link link : linkService.getLinks()) {
634 if (link.type() == Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700635 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700636 }
637 }
638 for (Link link : linkService.getLinks()) {
639 if (link.type() != Link.Type.OPTICAL) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700640 sendMessage(composeLinkMessage(new LinkEvent(LINK_ADDED, link)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700641 }
642 }
643 }
644
Simon Hunt5c1a9382016-06-01 19:35:35 -0700645 // Temporary mechanism to support topology overlays adding their own
646 // properties to the link events.
647 private ObjectNode composeLinkMessage(LinkEvent event) {
648 // start with base message
649 ObjectNode msg = linkMessage(event);
650 Map<String, String> additional =
651 overlayCache.currentOverlay().additionalLinkData(event);
652
653 if (additional != null) {
654 // attach additional key-value pairs as extra data structure
655 ObjectNode payload = (ObjectNode) msg.get(PAYLOAD);
656 payload.set(EXTRA, createExtra(additional));
657 }
658 return msg;
659 }
660
661 private ObjectNode createExtra(Map<String, String> additional) {
662 ObjectNode extra = objectNode();
663 for (Map.Entry<String, String> entry : additional.entrySet()) {
664 extra.put(entry.getKey(), entry.getValue());
665 }
666 return extra;
667 }
668
Thomas Vachuska329af532015-03-10 02:08:33 -0700669 // Sends all hosts to the client as host-added messages.
670 private void sendAllHosts() {
671 for (Host host : hostService.getHosts()) {
672 sendMessage(hostMessage(new HostEvent(HOST_ADDED, host)));
673 }
674 }
675
Thomas Vachuska329af532015-03-10 02:08:33 -0700676 private Set<ConnectPoint> getHostLocations(Set<HostId> hostIds) {
677 Set<ConnectPoint> points = new HashSet<>();
678 for (HostId hostId : hostIds) {
679 points.add(getHostLocation(hostId));
680 }
681 return points;
682 }
683
684 private HostLocation getHostLocation(HostId hostId) {
685 return hostService.getHost(hostId).location();
686 }
687
688 // Produces a list of host ids from the specified JSON array.
689 private Set<HostId> getHostIds(ArrayNode ids) {
690 Set<HostId> hostIds = new HashSet<>();
691 for (JsonNode id : ids) {
692 hostIds.add(hostId(id.asText()));
693 }
694 return hostIds;
695 }
696
Simon Hunt4a6b54b2015-10-27 22:08:25 -0700697 private void sendTopoStartDone() {
698 sendMessage(JsonUtils.envelope(TOPO_START_DONE, objectNode()));
699 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700700
Simon Huntd2747a02015-04-30 22:41:16 -0700701 private synchronized void startSummaryMonitoring() {
Thomas Vachuska329af532015-03-10 02:08:33 -0700702 stopSummaryMonitoring();
Thomas Vachuska329af532015-03-10 02:08:33 -0700703 summaryTask = new SummaryMonitor();
Simon Hunta17fa672015-08-19 18:42:22 -0700704 timer.schedule(summaryTask, SUMMARY_PERIOD, SUMMARY_PERIOD);
Simon Huntd2747a02015-04-30 22:41:16 -0700705 summaryRunning = true;
Thomas Vachuska329af532015-03-10 02:08:33 -0700706 }
707
708 private synchronized void stopSummaryMonitoring() {
Simon Huntd2747a02015-04-30 22:41:16 -0700709 if (summaryTask != null) {
Thomas Vachuska329af532015-03-10 02:08:33 -0700710 summaryTask.cancel();
711 summaryTask = null;
Thomas Vachuska329af532015-03-10 02:08:33 -0700712 }
Simon Huntd2747a02015-04-30 22:41:16 -0700713 summaryRunning = false;
Thomas Vachuska9ed335b2015-04-14 12:07:47 -0700714 }
715
Thomas Vachuska329af532015-03-10 02:08:33 -0700716
717 // Adds all internal listeners.
Thomas Vachuska35fa3d42015-04-30 10:11:47 -0700718 private synchronized void addListeners() {
Thomas Vachuskae586b792015-03-26 13:59:38 -0700719 listenersRemoved = false;
Thomas Vachuska329af532015-03-10 02:08:33 -0700720 clusterService.addListener(clusterListener);
721 mastershipService.addListener(mastershipListener);
722 deviceService.addListener(deviceListener);
723 linkService.addListener(linkListener);
724 hostService.addListener(hostListener);
725 intentService.addListener(intentListener);
726 flowService.addListener(flowListener);
727 }
728
729 // Removes all internal listeners.
730 private synchronized void removeListeners() {
731 if (!listenersRemoved) {
732 listenersRemoved = true;
733 clusterService.removeListener(clusterListener);
734 mastershipService.removeListener(mastershipListener);
735 deviceService.removeListener(deviceListener);
736 linkService.removeListener(linkListener);
737 hostService.removeListener(hostListener);
738 intentService.removeListener(intentListener);
739 flowService.removeListener(flowListener);
740 }
741 }
742
743 // Cluster event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700744 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
745 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700746 private class InternalClusterListener implements ClusterEventListener {
747 @Override
748 public void event(ClusterEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700749 msgSender.execute(() -> sendMessage(instanceMessage(event, null)));
Thomas Vachuska329af532015-03-10 02:08:33 -0700750 }
751 }
752
753 // Mastership change listener
Simon Hunt7092cc42016-04-06 18:40:17 -0700754 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
755 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700756 private class InternalMastershipListener implements MastershipListener {
757 @Override
758 public void event(MastershipEvent event) {
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700759 msgSender.execute(() -> {
Simon Huntb745ca62015-07-28 15:37:11 -0700760 sendAllInstances(UPDATE_INSTANCE);
Thomas Vachuska52c98bd2015-05-27 20:54:02 -0700761 Device device = deviceService.getDevice(event.subject());
762 if (device != null) {
763 sendMessage(deviceMessage(new DeviceEvent(DEVICE_UPDATED, device)));
764 }
765 });
Thomas Vachuska329af532015-03-10 02:08:33 -0700766 }
767 }
768
769 // Device event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700770 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
771 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700772 private class InternalDeviceListener implements DeviceListener {
773 @Override
774 public void event(DeviceEvent event) {
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700775 if (event.type() != PORT_STATS_UPDATED) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700776 msgSender.execute(() -> sendMessage(deviceMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800777 msgSender.execute(traffic::pokeIntent);
Thomas Vachuskacb5016f2015-05-18 14:11:43 -0700778 eventAccummulator.add(event);
779 }
Thomas Vachuska329af532015-03-10 02:08:33 -0700780 }
781 }
782
783 // Link event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700784 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
785 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700786 private class InternalLinkListener implements LinkListener {
787 @Override
788 public void event(LinkEvent event) {
Simon Hunt5c1a9382016-06-01 19:35:35 -0700789 msgSender.execute(() -> sendMessage(composeLinkMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800790 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700791 eventAccummulator.add(event);
792 }
793 }
794
795 // Host event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700796 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
797 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700798 private class InternalHostListener implements HostListener {
799 @Override
800 public void event(HostEvent event) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700801 msgSender.execute(() -> sendMessage(hostMessage(event)));
Simon Hunta1f1c022016-03-03 15:54:57 -0800802 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700803 eventAccummulator.add(event);
804 }
805 }
806
807 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700808 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
809 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700810 private class InternalIntentListener implements IntentListener {
811 @Override
812 public void event(IntentEvent event) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700813 msgSender.execute(traffic::pokeIntent);
Thomas Vachuska329af532015-03-10 02:08:33 -0700814 eventAccummulator.add(event);
815 }
816 }
817
818 // Intent event listener.
Simon Hunt7092cc42016-04-06 18:40:17 -0700819 // TODO: Superceded by UiSharedTopologyModel.ModelEventListener
820 @Deprecated
Thomas Vachuska329af532015-03-10 02:08:33 -0700821 private class InternalFlowListener implements FlowRuleListener {
822 @Override
823 public void event(FlowRuleEvent event) {
824 eventAccummulator.add(event);
825 }
826 }
827
Simon Huntd2747a02015-04-30 22:41:16 -0700828
Simon Hunta17fa672015-08-19 18:42:22 -0700829 // === SUMMARY MONITORING
Thomas Vachuska329af532015-03-10 02:08:33 -0700830
831 // Periodic update of the summary information
832 private class SummaryMonitor extends TimerTask {
833 @Override
834 public void run() {
835 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700836 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700837 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700838 }
839 } catch (Exception e) {
840 log.warn("Unable to handle summary request due to {}", e.getMessage());
841 log.warn("Boom!", e);
842 }
843 }
844 }
845
846 // Accumulates events to drive methodic update of the summary pane.
847 private class InternalEventAccummulator extends AbstractAccumulator<Event> {
848 protected InternalEventAccummulator() {
849 super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
850 }
851
852 @Override
853 public void processItems(List<Event> items) {
Simon Hunta17fa672015-08-19 18:42:22 -0700854 // Start-of-Debugging -- Keep in until ONOS-2572 is fixed for reals
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700855 long now = System.currentTimeMillis();
856 String me = this.toString();
857 String miniMe = me.replaceAll("^.*@", "me@");
858 log.debug("Time: {}; this: {}, processing items ({} events)",
Simon Hunt5c1a9382016-06-01 19:35:35 -0700859 now, miniMe, items.size());
Simon Hunt8d22c4b2015-08-06 16:24:43 -0700860 // End-of-Debugging
861
Thomas Vachuska329af532015-03-10 02:08:33 -0700862 try {
Simon Huntd2747a02015-04-30 22:41:16 -0700863 if (summaryRunning) {
Thomas Vachuskac7f79962015-05-28 09:37:34 -0700864 msgSender.execute(() -> requestSummary(0));
Thomas Vachuska329af532015-03-10 02:08:33 -0700865 }
866 } catch (Exception e) {
867 log.warn("Unable to handle summary request due to {}", e.getMessage());
868 log.debug("Boom!", e);
869 }
870 }
871 }
872}