blob: cea58999cc32af9ea66959bb01d27cc97ddb7e77 [file] [log] [blame]
Simon Hunta17fa672015-08-19 18:42:22 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.onosproject.ui.impl;
19
20import com.google.common.collect.ImmutableList;
21import org.onosproject.net.Device;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.Host;
24import org.onosproject.net.Link;
Simon Hunta17fa672015-08-19 18:42:22 -070025import org.onosproject.net.PortNumber;
26import org.onosproject.net.flow.FlowEntry;
27import org.onosproject.net.flow.TrafficTreatment;
28import org.onosproject.net.flow.instructions.Instruction;
29import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
30import org.onosproject.net.intent.FlowRuleIntent;
31import org.onosproject.net.intent.Intent;
32import org.onosproject.net.intent.LinkCollectionIntent;
33import org.onosproject.net.intent.OpticalConnectivityIntent;
34import org.onosproject.net.intent.OpticalPathIntent;
35import org.onosproject.net.intent.PathIntent;
36import org.onosproject.net.statistic.Load;
Simon Hunta17fa672015-08-19 18:42:22 -070037import org.onosproject.ui.impl.topo.IntentSelection;
Simon Hunta17fa672015-08-19 18:42:22 -070038import org.onosproject.ui.impl.topo.NodeSelection;
39import org.onosproject.ui.impl.topo.ServicesBundle;
40import org.onosproject.ui.impl.topo.TopoUtils;
Simon Hunt4fc86852015-08-20 17:57:52 -070041import org.onosproject.ui.impl.topo.TopoIntentFilter;
Simon Hunta17fa672015-08-19 18:42:22 -070042import org.onosproject.ui.impl.topo.TrafficClass;
Simon Hunt4fc86852015-08-20 17:57:52 -070043import org.onosproject.ui.impl.topo.TrafficLink;
44import org.onosproject.ui.impl.topo.TrafficLinkMap;
Simon Hunta17fa672015-08-19 18:42:22 -070045import org.onosproject.ui.topo.Highlights;
46import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.util.ArrayList;
50import java.util.Collection;
51import java.util.Collections;
52import java.util.HashMap;
53import java.util.HashSet;
54import java.util.List;
55import java.util.Map;
56import java.util.Set;
57import java.util.Timer;
58import java.util.TimerTask;
59
60import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Simon Hunt4fc86852015-08-20 17:57:52 -070061import static org.onosproject.ui.impl.TrafficMonitor.Mode.IDLE;
62import static org.onosproject.ui.impl.TrafficMonitor.Mode.SELECTED_INTENT;
Simon Hunta17fa672015-08-19 18:42:22 -070063import static org.onosproject.ui.topo.LinkHighlight.Flavor.PRIMARY_HIGHLIGHT;
64import static org.onosproject.ui.topo.LinkHighlight.Flavor.SECONDARY_HIGHLIGHT;
65
66/**
67 * Encapsulates the behavior of monitoring specific traffic patterns.
68 */
Simon Hunt4fc86852015-08-20 17:57:52 -070069public class TrafficMonitor {
Simon Hunta17fa672015-08-19 18:42:22 -070070
71 // 4 Kilo Bytes as threshold
72 private static final double BPS_THRESHOLD = 4 * TopoUtils.KILO;
73
74 private static final Logger log =
Simon Hunt4fc86852015-08-20 17:57:52 -070075 LoggerFactory.getLogger(TrafficMonitor.class);
Simon Hunta17fa672015-08-19 18:42:22 -070076
77 /**
78 * Designates the different modes of operation.
79 */
80 public enum Mode {
81 IDLE,
82 ALL_FLOW_TRAFFIC,
83 ALL_PORT_TRAFFIC,
84 DEV_LINK_FLOWS,
85 RELATED_INTENTS,
Simon Hunt4fc86852015-08-20 17:57:52 -070086 SELECTED_INTENT
Simon Hunta17fa672015-08-19 18:42:22 -070087 }
88
89 private final long trafficPeriod;
90 private final ServicesBundle servicesBundle;
Simon Hunt4fc86852015-08-20 17:57:52 -070091 private final TopologyViewMessageHandler msgHandler;
92 private final TopoIntentFilter intentFilter;
Simon Hunta17fa672015-08-19 18:42:22 -070093
94 private final Timer timer = new Timer("topo-traffic");
95
96 private TimerTask trafficTask = null;
97 private Mode mode = IDLE;
98 private NodeSelection selectedNodes = null;
99 private IntentSelection selectedIntents = null;
100
101
102 /**
103 * Constructs a traffic monitor.
104 *
105 * @param trafficPeriod traffic task period in ms
106 * @param servicesBundle bundle of services
Simon Hunt4fc86852015-08-20 17:57:52 -0700107 * @param msgHandler our message handler
Simon Hunta17fa672015-08-19 18:42:22 -0700108 */
Simon Hunt4fc86852015-08-20 17:57:52 -0700109 public TrafficMonitor(long trafficPeriod, ServicesBundle servicesBundle,
110 TopologyViewMessageHandler msgHandler) {
Simon Hunta17fa672015-08-19 18:42:22 -0700111 this.trafficPeriod = trafficPeriod;
112 this.servicesBundle = servicesBundle;
Simon Hunt4fc86852015-08-20 17:57:52 -0700113 this.msgHandler = msgHandler;
Simon Hunta17fa672015-08-19 18:42:22 -0700114
Simon Hunt4fc86852015-08-20 17:57:52 -0700115 intentFilter = new TopoIntentFilter(servicesBundle);
Simon Hunta17fa672015-08-19 18:42:22 -0700116 }
117
118 // =======================================================================
Simon Hunt4fc86852015-08-20 17:57:52 -0700119 // === API ===
Simon Hunta17fa672015-08-19 18:42:22 -0700120
Simon Hunt4fc86852015-08-20 17:57:52 -0700121 /**
122 * Monitor for traffic data to be sent back to the web client, under
123 * the given mode. This causes a background traffic task to be
124 * scheduled to repeatedly compute and transmit the appropriate traffic
125 * data to the client.
126 * <p>
127 * The monitoring mode is expected to be one of:
128 * <ul>
129 * <li>ALL_FLOW_TRAFFIC</li>
130 * <li>ALL_PORT_TRAFFIC</li>
131 * <li>SELECTED_INTENT</li>
132 * </ul>
133 *
134 * @param mode monitoring mode
135 */
Simon Hunta17fa672015-08-19 18:42:22 -0700136 public synchronized void monitor(Mode mode) {
137 log.debug("monitor: {}", mode);
138 this.mode = mode;
139
140 switch (mode) {
141 case ALL_FLOW_TRAFFIC:
142 clearSelection();
143 scheduleTask();
144 sendAllFlowTraffic();
145 break;
146
147 case ALL_PORT_TRAFFIC:
148 clearSelection();
149 scheduleTask();
150 sendAllPortTraffic();
151 break;
152
Simon Hunt4fc86852015-08-20 17:57:52 -0700153 case SELECTED_INTENT:
Simon Hunta17fa672015-08-19 18:42:22 -0700154 scheduleTask();
155 sendSelectedIntentTraffic();
156 break;
157
158 default:
159 log.debug("Unexpected call to monitor({})", mode);
160 clearAll();
161 break;
162 }
163 }
164
Simon Hunt4fc86852015-08-20 17:57:52 -0700165 /**
166 * Monitor for traffic data to be sent back to the web client, under
167 * the given mode, using the given selection of devices and hosts.
168 * In the case of "device link flows", this causes a background traffic
169 * task to be scheduled to repeatedly compute and transmit the appropriate
170 * traffic data to the client. In the case of "related intents", no
171 * repeating task is scheduled.
172 * <p>
173 * The monitoring mode is expected to be one of:
174 * <ul>
175 * <li>DEV_LINK_FLOWS</li>
176 * <li>RELATED_INTENTS</li>
177 * </ul>
178 *
179 * @param mode monitoring mode
180 */
Simon Hunta17fa672015-08-19 18:42:22 -0700181 public synchronized void monitor(Mode mode, NodeSelection nodeSelection) {
182 log.debug("monitor: {} -- {}", mode, nodeSelection);
183 this.mode = mode;
184 this.selectedNodes = nodeSelection;
185
186 switch (mode) {
187 case DEV_LINK_FLOWS:
188 // only care about devices (not hosts)
189 if (selectedNodes.devices().isEmpty()) {
190 sendClearAll();
191 } else {
192 scheduleTask();
193 sendDeviceLinkFlows();
194 }
195 break;
196
197 case RELATED_INTENTS:
198 if (selectedNodes.none()) {
199 sendClearAll();
200 } else {
201 selectedIntents = new IntentSelection(selectedNodes, intentFilter);
202 if (selectedIntents.none()) {
203 sendClearAll();
204 } else {
205 sendSelectedIntents();
206 }
207 }
208 break;
209
210 default:
211 log.debug("Unexpected call to monitor({}, {})", mode, nodeSelection);
212 clearAll();
213 break;
214 }
215 }
216
Simon Hunt4fc86852015-08-20 17:57:52 -0700217 // TODO: move this out to the "h2h/multi-intent app"
218 /**
219 * Monitor for traffic data to be sent back to the web client, for the
220 * given intent.
221 *
222 * @param intent the intent to monitor
223 */
Simon Hunta17fa672015-08-19 18:42:22 -0700224 public synchronized void monitor(Intent intent) {
225 log.debug("monitor intent: {}", intent.id());
226 selectedNodes = null;
227 selectedIntents = new IntentSelection(intent);
Simon Hunt4fc86852015-08-20 17:57:52 -0700228 mode = SELECTED_INTENT;
Simon Hunta17fa672015-08-19 18:42:22 -0700229 scheduleTask();
230 sendSelectedIntentTraffic();
231 }
232
Simon Hunt4fc86852015-08-20 17:57:52 -0700233 /**
234 * Selects the next intent in the select group (if there is one),
235 * and sends highlighting data back to the web client to display
236 * which path is selected.
237 */
Simon Hunta17fa672015-08-19 18:42:22 -0700238 public synchronized void selectNextIntent() {
239 if (selectedIntents != null) {
240 selectedIntents.next();
241 sendSelectedIntents();
242 }
243 }
244
Simon Hunt4fc86852015-08-20 17:57:52 -0700245 /**
246 * Selects the previous intent in the select group (if there is one),
247 * and sends highlighting data back to the web client to display
248 * which path is selected.
249 */
Simon Hunta17fa672015-08-19 18:42:22 -0700250 public synchronized void selectPreviousIntent() {
251 if (selectedIntents != null) {
252 selectedIntents.prev();
253 sendSelectedIntents();
254 }
255 }
256
Simon Hunt4fc86852015-08-20 17:57:52 -0700257 /**
258 * Resends selected intent traffic data. This is called, for example,
259 * when the system detects an intent update happened.
260 */
Simon Hunta17fa672015-08-19 18:42:22 -0700261 public synchronized void pokeIntent() {
Simon Hunt4fc86852015-08-20 17:57:52 -0700262 if (mode == SELECTED_INTENT) {
Simon Hunta17fa672015-08-19 18:42:22 -0700263 sendSelectedIntentTraffic();
264 }
265 }
266
Simon Hunt4fc86852015-08-20 17:57:52 -0700267 /**
268 * Stop all traffic monitoring.
269 */
270 public synchronized void stopMonitoring() {
271 log.debug("STOP monitoring");
Simon Hunta17fa672015-08-19 18:42:22 -0700272 if (mode != IDLE) {
273 sendClearAll();
274 }
275 }
276
277
278 // =======================================================================
279 // === Helper methods ===
280
281 private void sendClearAll() {
282 clearAll();
283 sendClearHighlights();
284 }
285
286 private void clearAll() {
287 this.mode = IDLE;
288 clearSelection();
289 cancelTask();
290 }
291
292 private void clearSelection() {
293 selectedNodes = null;
294 selectedIntents = null;
295 }
296
297 private synchronized void scheduleTask() {
298 if (trafficTask == null) {
299 log.debug("Starting up background traffic task...");
Simon Hunt4fc86852015-08-20 17:57:52 -0700300 trafficTask = new TrafficUpdateTask();
Simon Hunta17fa672015-08-19 18:42:22 -0700301 timer.schedule(trafficTask, trafficPeriod, trafficPeriod);
302 } else {
303 // TEMPORARY until we are sure this is working correctly
304 log.debug("(traffic task already running)");
305 }
306 }
307
308 private synchronized void cancelTask() {
309 if (trafficTask != null) {
310 trafficTask.cancel();
311 trafficTask = null;
312 }
313 }
314
Simon Hunta17fa672015-08-19 18:42:22 -0700315 private void sendAllFlowTraffic() {
316 log.debug("sendAllFlowTraffic");
Simon Hunt4fc86852015-08-20 17:57:52 -0700317 msgHandler.sendHighlights(trafficSummary(TrafficLink.StatsType.FLOW_STATS));
Simon Hunta17fa672015-08-19 18:42:22 -0700318 }
319
320 private void sendAllPortTraffic() {
321 log.debug("sendAllPortTraffic");
Simon Hunt4fc86852015-08-20 17:57:52 -0700322 msgHandler.sendHighlights(trafficSummary(TrafficLink.StatsType.PORT_STATS));
Simon Hunta17fa672015-08-19 18:42:22 -0700323 }
324
325 private void sendDeviceLinkFlows() {
326 log.debug("sendDeviceLinkFlows: {}", selectedNodes);
Simon Hunt4fc86852015-08-20 17:57:52 -0700327 msgHandler.sendHighlights(deviceLinkFlows());
Simon Hunta17fa672015-08-19 18:42:22 -0700328 }
329
330 private void sendSelectedIntents() {
331 log.debug("sendSelectedIntents: {}", selectedIntents);
Simon Hunt4fc86852015-08-20 17:57:52 -0700332 msgHandler.sendHighlights(intentGroup());
Simon Hunta17fa672015-08-19 18:42:22 -0700333 }
334
335 private void sendSelectedIntentTraffic() {
336 log.debug("sendSelectedIntentTraffic: {}", selectedIntents);
Simon Hunt4fc86852015-08-20 17:57:52 -0700337 msgHandler.sendHighlights(intentTraffic());
Simon Hunta17fa672015-08-19 18:42:22 -0700338 }
339
340 private void sendClearHighlights() {
341 log.debug("sendClearHighlights");
Simon Hunt4fc86852015-08-20 17:57:52 -0700342 msgHandler.sendHighlights(new Highlights());
Simon Hunta17fa672015-08-19 18:42:22 -0700343 }
344
Simon Hunta17fa672015-08-19 18:42:22 -0700345 // =======================================================================
346 // === Generate messages in JSON object node format
347
Simon Hunt4fc86852015-08-20 17:57:52 -0700348 private Highlights trafficSummary(TrafficLink.StatsType type) {
Simon Hunta17fa672015-08-19 18:42:22 -0700349 Highlights highlights = new Highlights();
350
Simon Hunt4fc86852015-08-20 17:57:52 -0700351 TrafficLinkMap linkMap = new TrafficLinkMap();
Simon Hunta17fa672015-08-19 18:42:22 -0700352 compileLinks(linkMap);
353 addEdgeLinks(linkMap);
354
Simon Hunt4fc86852015-08-20 17:57:52 -0700355 for (TrafficLink tlink : linkMap.biLinks()) {
356 if (type == TrafficLink.StatsType.FLOW_STATS) {
357 attachFlowLoad(tlink);
358 } else if (type == TrafficLink.StatsType.PORT_STATS) {
359 attachPortLoad(tlink);
Simon Hunta17fa672015-08-19 18:42:22 -0700360 }
361
362 // we only want to report on links deemed to have traffic
Simon Hunt4fc86852015-08-20 17:57:52 -0700363 if (tlink.hasTraffic()) {
364 highlights.add(tlink.highlight(type));
Simon Hunta17fa672015-08-19 18:42:22 -0700365 }
366 }
367 return highlights;
368 }
369
370 // create highlights for links, showing flows for selected devices.
371 private Highlights deviceLinkFlows() {
372 Highlights highlights = new Highlights();
373
374 if (selectedNodes != null && !selectedNodes.devices().isEmpty()) {
375 // capture flow counts on bilinks
Simon Hunt4fc86852015-08-20 17:57:52 -0700376 TrafficLinkMap linkMap = new TrafficLinkMap();
Simon Hunta17fa672015-08-19 18:42:22 -0700377
378 for (Device device : selectedNodes.devices()) {
379 Map<Link, Integer> counts = getLinkFlowCounts(device.id());
380 for (Link link : counts.keySet()) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700381 TrafficLink tlink = linkMap.add(link);
382 tlink.addFlows(counts.get(link));
Simon Hunta17fa672015-08-19 18:42:22 -0700383 }
384 }
385
386 // now report on our collated links
Simon Hunt4fc86852015-08-20 17:57:52 -0700387 for (TrafficLink tlink : linkMap.biLinks()) {
388 highlights.add(tlink.highlight(TrafficLink.StatsType.FLOW_COUNT));
Simon Hunta17fa672015-08-19 18:42:22 -0700389 }
390
391 }
392 return highlights;
393 }
394
395 private Highlights intentGroup() {
396 Highlights highlights = new Highlights();
397
398 if (selectedIntents != null && !selectedIntents.none()) {
399 // If 'all' intents are selected, they will all have primary
400 // highlighting; otherwise, the specifically selected intent will
401 // have primary highlighting, and the remainder will have secondary
402 // highlighting.
403 Set<Intent> primary;
404 Set<Intent> secondary;
405 int count = selectedIntents.size();
406
407 Set<Intent> allBut = new HashSet<>(selectedIntents.intents());
408 Intent current;
409
410 if (selectedIntents.all()) {
411 primary = allBut;
412 secondary = Collections.emptySet();
413 log.debug("Highlight all intents ({})", count);
414 } else {
415 current = selectedIntents.current();
416 primary = new HashSet<>();
417 primary.add(current);
418 allBut.remove(current);
419 secondary = allBut;
420 log.debug("Highlight intent: {} ([{}] of {})",
421 current.id(), selectedIntents.index(), count);
422 }
423 TrafficClass tc1 = new TrafficClass(PRIMARY_HIGHLIGHT, primary);
424 TrafficClass tc2 = new TrafficClass(SECONDARY_HIGHLIGHT, secondary);
425 // classify primary links after secondary (last man wins)
426 highlightIntents(highlights, tc2, tc1);
427 }
428 return highlights;
429 }
430
431 private Highlights intentTraffic() {
432 Highlights highlights = new Highlights();
433
434 if (selectedIntents != null && selectedIntents.single()) {
435 Intent current = selectedIntents.current();
436 Set<Intent> primary = new HashSet<>();
437 primary.add(current);
438 log.debug("Highlight traffic for intent: {} ([{}] of {})",
439 current.id(), selectedIntents.index(), selectedIntents.size());
440 TrafficClass tc1 = new TrafficClass(PRIMARY_HIGHLIGHT, primary, true);
441 highlightIntents(highlights, tc1);
442 }
443 return highlights;
444 }
445
Simon Hunta17fa672015-08-19 18:42:22 -0700446 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
447
Simon Hunt4fc86852015-08-20 17:57:52 -0700448 private void compileLinks(TrafficLinkMap linkMap) {
449 servicesBundle.linkService().getLinks().forEach(linkMap::add);
Simon Hunta17fa672015-08-19 18:42:22 -0700450 }
451
Simon Hunt4fc86852015-08-20 17:57:52 -0700452 private void addEdgeLinks(TrafficLinkMap linkMap) {
Simon Hunta17fa672015-08-19 18:42:22 -0700453 servicesBundle.hostService().getHosts().forEach(host -> {
Simon Hunt4fc86852015-08-20 17:57:52 -0700454 linkMap.add(createEdgeLink(host, true));
455 linkMap.add(createEdgeLink(host, false));
Simon Hunta17fa672015-08-19 18:42:22 -0700456 });
457 }
458
459 private Load getLinkFlowLoad(Link link) {
460 if (link != null && link.src().elementId() instanceof DeviceId) {
461 return servicesBundle.flowStatsService().load(link);
462 }
463 return null;
464 }
465
Simon Hunt4fc86852015-08-20 17:57:52 -0700466 private void attachFlowLoad(TrafficLink link) {
Simon Hunta17fa672015-08-19 18:42:22 -0700467 link.addLoad(getLinkFlowLoad(link.one()));
468 link.addLoad(getLinkFlowLoad(link.two()));
469 }
470
Simon Hunt4fc86852015-08-20 17:57:52 -0700471 private void attachPortLoad(TrafficLink link) {
Simon Hunta17fa672015-08-19 18:42:22 -0700472 // For bi-directional traffic links, use
473 // the max link rate of either direction
474 // (we choose 'one' since we know that is never null)
475 Link one = link.one();
476 Load egressSrc = servicesBundle.portStatsService().load(one.src());
477 Load egressDst = servicesBundle.portStatsService().load(one.dst());
Simon Hunt5f31a022015-08-20 08:43:25 -0700478 link.addLoad(maxLoad(egressSrc, egressDst), BPS_THRESHOLD);
Simon Hunt4fc86852015-08-20 17:57:52 -0700479// link.addLoad(maxLoad(egressSrc, egressDst), 10); // DEBUG ONLY!!
Simon Hunta17fa672015-08-19 18:42:22 -0700480 }
481
482 private Load maxLoad(Load a, Load b) {
483 if (a == null) {
484 return b;
485 }
486 if (b == null) {
487 return a;
488 }
489 return a.rate() > b.rate() ? a : b;
490 }
491
Simon Hunta17fa672015-08-19 18:42:22 -0700492 // Counts all flow entries that egress on the links of the given device.
493 private Map<Link, Integer> getLinkFlowCounts(DeviceId deviceId) {
494 // get the flows for the device
495 List<FlowEntry> entries = new ArrayList<>();
Simon Hunt4fc86852015-08-20 17:57:52 -0700496 for (FlowEntry flowEntry : servicesBundle.flowService()
497 .getFlowEntries(deviceId)) {
Simon Hunta17fa672015-08-19 18:42:22 -0700498 entries.add(flowEntry);
499 }
500
501 // get egress links from device, and include edge links
Simon Hunt4fc86852015-08-20 17:57:52 -0700502 Set<Link> links = new HashSet<>(servicesBundle.linkService()
503 .getDeviceEgressLinks(deviceId));
Simon Hunta17fa672015-08-19 18:42:22 -0700504 Set<Host> hosts = servicesBundle.hostService().getConnectedHosts(deviceId);
505 if (hosts != null) {
506 for (Host host : hosts) {
507 links.add(createEdgeLink(host, false));
508 }
509 }
510
511 // compile flow counts per link
512 Map<Link, Integer> counts = new HashMap<>();
513 for (Link link : links) {
514 counts.put(link, getEgressFlows(link, entries));
515 }
516 return counts;
517 }
518
519 // Counts all entries that egress on the link source port.
520 private int getEgressFlows(Link link, List<FlowEntry> entries) {
521 int count = 0;
522 PortNumber out = link.src().port();
523 for (FlowEntry entry : entries) {
524 TrafficTreatment treatment = entry.treatment();
525 for (Instruction instruction : treatment.allInstructions()) {
526 if (instruction.type() == Instruction.Type.OUTPUT &&
527 ((OutputInstruction) instruction).port().equals(out)) {
528 count++;
529 }
530 }
531 }
532 return count;
533 }
534
Simon Hunta17fa672015-08-19 18:42:22 -0700535 private void highlightIntents(Highlights highlights,
536 TrafficClass... trafficClasses) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700537 TrafficLinkMap linkMap = new TrafficLinkMap();
Simon Hunta17fa672015-08-19 18:42:22 -0700538
539 for (TrafficClass trafficClass : trafficClasses) {
540 classifyLinkTraffic(linkMap, trafficClass);
541 }
542
Simon Hunt4fc86852015-08-20 17:57:52 -0700543 for (TrafficLink tlink : linkMap.biLinks()) {
544 highlights.add(tlink.highlight(TrafficLink.StatsType.TAGGED));
Simon Hunta17fa672015-08-19 18:42:22 -0700545 }
546 }
547
Simon Hunt4fc86852015-08-20 17:57:52 -0700548 private void classifyLinkTraffic(TrafficLinkMap linkMap,
Simon Hunta17fa672015-08-19 18:42:22 -0700549 TrafficClass trafficClass) {
550 for (Intent intent : trafficClass.intents()) {
551 boolean isOptical = intent instanceof OpticalConnectivityIntent;
552 List<Intent> installables = servicesBundle.intentService()
553 .getInstallableIntents(intent.key());
554 Iterable<Link> links = null;
555
556 if (installables != null) {
557 for (Intent installable : installables) {
558
559 if (installable instanceof PathIntent) {
560 links = ((PathIntent) installable).path().links();
561 } else if (installable instanceof FlowRuleIntent) {
562 links = linkResources(installable);
563 } else if (installable instanceof LinkCollectionIntent) {
564 links = ((LinkCollectionIntent) installable).links();
565 } else if (installable instanceof OpticalPathIntent) {
566 links = ((OpticalPathIntent) installable).path().links();
567 }
568
569 classifyLinks(trafficClass, isOptical, linkMap, links);
570 }
571 }
572 }
573 }
574
575 private void classifyLinks(TrafficClass trafficClass, boolean isOptical,
Simon Hunt4fc86852015-08-20 17:57:52 -0700576 TrafficLinkMap linkMap,
Simon Hunta17fa672015-08-19 18:42:22 -0700577 Iterable<Link> links) {
578 if (links != null) {
579 for (Link link : links) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700580 TrafficLink tlink = linkMap.add(link);
Simon Hunta17fa672015-08-19 18:42:22 -0700581 if (trafficClass.showTraffic()) {
Simon Hunt4fc86852015-08-20 17:57:52 -0700582 tlink.addLoad(getLinkFlowLoad(link));
583 tlink.antMarch(true);
Simon Hunta17fa672015-08-19 18:42:22 -0700584 }
Simon Hunt4fc86852015-08-20 17:57:52 -0700585 tlink.optical(isOptical);
586 tlink.tagFlavor(trafficClass.flavor());
Simon Hunta17fa672015-08-19 18:42:22 -0700587 }
588 }
589 }
590
591 // Extracts links from the specified flow rule intent resources
592 private Collection<Link> linkResources(Intent installable) {
593 ImmutableList.Builder<Link> builder = ImmutableList.builder();
594 installable.resources().stream().filter(r -> r instanceof Link)
595 .forEach(r -> builder.add((Link) r));
596 return builder.build();
597 }
598
599 // =======================================================================
600 // === Background Task
601
602 // Provides periodic update of traffic information to the client
Simon Hunt4fc86852015-08-20 17:57:52 -0700603 private class TrafficUpdateTask extends TimerTask {
Simon Hunta17fa672015-08-19 18:42:22 -0700604 @Override
605 public void run() {
606 try {
607 switch (mode) {
608 case ALL_FLOW_TRAFFIC:
609 sendAllFlowTraffic();
610 break;
611 case ALL_PORT_TRAFFIC:
612 sendAllPortTraffic();
613 break;
614 case DEV_LINK_FLOWS:
615 sendDeviceLinkFlows();
616 break;
Simon Hunt4fc86852015-08-20 17:57:52 -0700617 case SELECTED_INTENT:
Simon Hunta17fa672015-08-19 18:42:22 -0700618 sendSelectedIntentTraffic();
619 break;
620
621 default:
622 // RELATED_INTENTS and IDLE modes should never invoke
623 // the background task, but if they do, they have
624 // nothing to do
625 break;
626 }
627
628 } catch (Exception e) {
629 log.warn("Unable to process traffic task due to {}", e.getMessage());
630 log.warn("Boom!", e);
631 }
632 }
633 }
Simon Hunta17fa672015-08-19 18:42:22 -0700634}