Thomas Vachuska
Committed by Ray Milkey

Fixing various issues and re-tuning.

Change-Id: I8822fcf77cfa507788241c5bda98ef4741b284b4
...@@ -23,13 +23,15 @@ import org.onlab.onos.cluster.ControllerNode; ...@@ -23,13 +23,15 @@ import org.onlab.onos.cluster.ControllerNode;
23 import org.onlab.onos.mastership.MastershipAdminService; 23 import org.onlab.onos.mastership.MastershipAdminService;
24 import org.onlab.onos.mastership.MastershipService; 24 import org.onlab.onos.mastership.MastershipService;
25 import org.onlab.onos.net.DeviceId; 25 import org.onlab.onos.net.DeviceId;
26 -import org.onlab.onos.net.MastershipRole; 26 +import org.onlab.onos.net.device.DeviceService;
27 27
28 import java.util.Collection; 28 import java.util.Collection;
29 import java.util.Iterator; 29 import java.util.Iterator;
30 import java.util.List; 30 import java.util.List;
31 +import java.util.Set;
31 32
32 import static com.google.common.collect.Lists.newArrayList; 33 import static com.google.common.collect.Lists.newArrayList;
34 +import static org.onlab.onos.net.MastershipRole.MASTER;
33 35
34 /** 36 /**
35 * Forces device mastership rebalancing. 37 * Forces device mastership rebalancing.
...@@ -50,73 +52,62 @@ public class BalanceMastersCommand extends AbstractShellCommand { ...@@ -50,73 +52,62 @@ public class BalanceMastersCommand extends AbstractShellCommand {
50 52
51 // Create buckets reflecting current ownership. 53 // Create buckets reflecting current ownership.
52 for (ControllerNode node : nodes) { 54 for (ControllerNode node : nodes) {
53 - controllerDevices.putAll(node, mastershipService.getDevicesOf(node.id())); 55 + Set<DeviceId> devicesOf = mastershipService.getDevicesOf(node.id());
56 + controllerDevices.putAll(node, devicesOf);
57 + print("Node %s has %d devices.", node.id(), devicesOf.size());
54 } 58 }
55 59
56 - int bucketCount = nodes.size(); 60 + int rounds = nodes.size();
57 - for (int i = 0; i < bucketCount / 2; i++) { 61 + for (int i = 0; i < rounds; i++) {
58 // Iterate over the buckets and find the smallest and the largest. 62 // Iterate over the buckets and find the smallest and the largest.
59 - ControllerNode smallest = findSmallestBucket(controllerDevices); 63 + ControllerNode smallest = findBucket(true, nodes, controllerDevices);
60 - ControllerNode largest = findLargestBucket(controllerDevices); 64 + ControllerNode largest = findBucket(false, nodes, controllerDevices);
61 - balanceBuckets(smallest, largest, controllerDevices, 65 + balanceBuckets(smallest, largest, controllerDevices, adminService);
62 - mastershipService, adminService);
63 } 66 }
64 } 67 }
65 68
66 - private ControllerNode findSmallestBucket(Multimap<ControllerNode, DeviceId> controllerDevices) { 69 + private ControllerNode findBucket(boolean min, Collection<ControllerNode> nodes,
67 - int minSize = Integer.MAX_VALUE; 70 + Multimap<ControllerNode, DeviceId> controllerDevices) {
68 - ControllerNode minNode = null; 71 + int xSize = min ? Integer.MAX_VALUE : -1;
69 - for (ControllerNode node : controllerDevices.keySet()) { 72 + ControllerNode xNode = null;
70 - int size = controllerDevices.get(node).size(); 73 + for (ControllerNode node : nodes) {
71 - if (size < minSize) {
72 - minSize = size;
73 - minNode = node;
74 - }
75 - }
76 - return minNode;
77 - }
78 -
79 - private ControllerNode findLargestBucket(Multimap<ControllerNode, DeviceId> controllerDevices) {
80 - int maxSize = -1;
81 - ControllerNode maxNode = null;
82 - for (ControllerNode node : controllerDevices.keySet()) {
83 int size = controllerDevices.get(node).size(); 74 int size = controllerDevices.get(node).size();
84 - if (size >= maxSize) { 75 + if ((min && size < xSize) || (!min && size > xSize)) {
85 - maxSize = size; 76 + xSize = size;
86 - maxNode = node; 77 + xNode = node;
87 } 78 }
88 } 79 }
89 - return maxNode; 80 + return xNode;
90 } 81 }
91 82
92 // FIXME: enhance to better handle cases where smallest cannot take any of the devices from largest 83 // FIXME: enhance to better handle cases where smallest cannot take any of the devices from largest
93 84
94 private void balanceBuckets(ControllerNode smallest, ControllerNode largest, 85 private void balanceBuckets(ControllerNode smallest, ControllerNode largest,
95 Multimap<ControllerNode, DeviceId> controllerDevices, 86 Multimap<ControllerNode, DeviceId> controllerDevices,
96 - MastershipService mastershipService,
97 MastershipAdminService adminService) { 87 MastershipAdminService adminService) {
98 Collection<DeviceId> minBucket = controllerDevices.get(smallest); 88 Collection<DeviceId> minBucket = controllerDevices.get(smallest);
99 Collection<DeviceId> maxBucket = controllerDevices.get(largest); 89 Collection<DeviceId> maxBucket = controllerDevices.get(largest);
90 + int bucketCount = controllerDevices.keySet().size();
91 + int deviceCount = get(DeviceService.class).getDeviceCount();
100 92
101 int delta = (maxBucket.size() - minBucket.size()) / 2; 93 int delta = (maxBucket.size() - minBucket.size()) / 2;
102 - 94 + delta = Math.min(deviceCount / bucketCount, delta);
103 - print("Attempting to move %d nodes from %s to %s...", 95 +
104 - delta, largest.id(), smallest.id()); 96 + if (delta > 0) {
105 - 97 + print("Attempting to move %d nodes from %s to %s...",
106 - int i = 0; 98 + delta, largest.id(), smallest.id());
107 - Iterator<DeviceId> it = maxBucket.iterator(); 99 +
108 - while (it.hasNext() && i < delta) { 100 + int i = 0;
109 - DeviceId deviceId = it.next(); 101 + Iterator<DeviceId> it = maxBucket.iterator();
110 - 102 + while (it.hasNext() && i < delta) {
111 - // Check that the transfer can happen for the current element. 103 + DeviceId deviceId = it.next();
112 - if (mastershipService.getNodesFor(deviceId).backups().contains(smallest.id())) { 104 + print("Setting %s as the master for %s", smallest.id(), deviceId);
113 - print("Setting %s as the new master for %s", smallest.id(), deviceId); 105 + adminService.setRole(smallest.id(), deviceId, MASTER);
114 - adminService.setRole(smallest.id(), deviceId, MastershipRole.MASTER); 106 + controllerDevices.put(smallest, deviceId);
107 + it.remove();
115 i++; 108 i++;
116 } 109 }
117 } 110 }
118 -
119 - controllerDevices.removeAll(smallest);
120 } 111 }
121 112
122 } 113 }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
16 package org.onlab.onos.event; 16 package org.onlab.onos.event;
17 17
18 import com.google.common.collect.Lists; 18 import com.google.common.collect.Lists;
19 +import org.slf4j.Logger;
20 +import org.slf4j.LoggerFactory;
19 21
20 import java.util.List; 22 import java.util.List;
21 import java.util.Timer; 23 import java.util.Timer;
...@@ -31,6 +33,8 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -31,6 +33,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
31 */ 33 */
32 public abstract class AbstractEventAccumulator implements EventAccumulator { 34 public abstract class AbstractEventAccumulator implements EventAccumulator {
33 35
36 + private Logger log = LoggerFactory.getLogger(AbstractEventAccumulator.class);
37 +
34 private final Timer timer; 38 private final Timer timer;
35 private final int maxEvents; 39 private final int maxEvents;
36 private final int maxBatchMillis; 40 private final int maxBatchMillis;
...@@ -104,9 +108,13 @@ public abstract class AbstractEventAccumulator implements EventAccumulator { ...@@ -104,9 +108,13 @@ public abstract class AbstractEventAccumulator implements EventAccumulator {
104 private class ProcessorTask extends TimerTask { 108 private class ProcessorTask extends TimerTask {
105 @Override 109 @Override
106 public void run() { 110 public void run() {
107 - idleTask = cancelIfActive(idleTask); 111 + try {
108 - maxTask = cancelIfActive(maxTask); 112 + idleTask = cancelIfActive(idleTask);
109 - processEvents(finalizeCurrentBatch()); 113 + maxTask = cancelIfActive(maxTask);
114 + processEvents(finalizeCurrentBatch());
115 + } catch (Exception e) {
116 + log.warn("Unable to process batch due to {}", e.getMessage());
117 + }
110 } 118 }
111 } 119 }
112 120
......
...@@ -66,13 +66,13 @@ public class DefaultTopologyProvider extends AbstractProvider ...@@ -66,13 +66,13 @@ public class DefaultTopologyProvider extends AbstractProvider
66 implements TopologyProvider { 66 implements TopologyProvider {
67 67
68 private static final int MAX_THREADS = 8; 68 private static final int MAX_THREADS = 8;
69 - private static final int DEFAULT_MAX_EVENTS = 100; 69 + private static final int DEFAULT_MAX_EVENTS = 200;
70 - private static final int DEFAULT_MAX_BATCH_MS = 50; 70 + private static final int DEFAULT_MAX_BATCH_MS = 60;
71 - private static final int DEFAULT_MAX_IDLE_MS = 5; 71 + private static final int DEFAULT_MAX_IDLE_MS = 30;
72 72
73 // FIXME: Replace with a system-wide timer instance; 73 // FIXME: Replace with a system-wide timer instance;
74 // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt 74 // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt
75 - private static final Timer TIMER = new Timer(); 75 + private static final Timer TIMER = new Timer("topo-event-batching");
76 76
77 @Property(name = "maxEvents", intValue = DEFAULT_MAX_EVENTS, 77 @Property(name = "maxEvents", intValue = DEFAULT_MAX_EVENTS,
78 label = "Maximum number of events to accumulate") 78 label = "Maximum number of events to accumulate")
...@@ -122,6 +122,9 @@ public class DefaultTopologyProvider extends AbstractProvider ...@@ -122,6 +122,9 @@ public class DefaultTopologyProvider extends AbstractProvider
122 deviceService.addListener(deviceListener); 122 deviceService.addListener(deviceListener);
123 linkService.addListener(linkListener); 123 linkService.addListener(linkListener);
124 124
125 + log.info("Configured with maxEvents = {}; maxBatchMs = {}; maxIdleMs = {}",
126 + maxEvents, maxBatchMs, maxIdleMs);
127 +
125 isStarted = true; 128 isStarted = true;
126 triggerRecompute(); 129 triggerRecompute();
127 log.info("Started"); 130 log.info("Started");
......
1 +#!/bin/bash
2 +# -----------------------------------------------------------------------------
3 +# ONOS topology configuration uploader.
4 +# -----------------------------------------------------------------------------
5 +
6 +[ ! -d "$ONOS_ROOT" ] && echo "ONOS_ROOT is not defined" >&2 && exit 1
7 +. $ONOS_ROOT/tools/build/envDefaults
8 +
9 +nodes=$(env | sort | egrep "OC[0-9]+" | cut -d= -f2)
10 +
11 +for node in $nodes; do
12 + printf "$node..."
13 + onos-topo-cfg $node $1
14 +done
15 +printf "\n"
...@@ -24,6 +24,9 @@ import org.onlab.onos.cluster.ClusterEventListener; ...@@ -24,6 +24,9 @@ import org.onlab.onos.cluster.ClusterEventListener;
24 import org.onlab.onos.cluster.ControllerNode; 24 import org.onlab.onos.cluster.ControllerNode;
25 import org.onlab.onos.core.ApplicationId; 25 import org.onlab.onos.core.ApplicationId;
26 import org.onlab.onos.core.CoreService; 26 import org.onlab.onos.core.CoreService;
27 +import org.onlab.onos.event.AbstractEventAccumulator;
28 +import org.onlab.onos.event.Event;
29 +import org.onlab.onos.event.EventAccumulator;
27 import org.onlab.onos.mastership.MastershipEvent; 30 import org.onlab.onos.mastership.MastershipEvent;
28 import org.onlab.onos.mastership.MastershipListener; 31 import org.onlab.onos.mastership.MastershipListener;
29 import org.onlab.onos.net.ConnectPoint; 32 import org.onlab.onos.net.ConnectPoint;
...@@ -36,6 +39,8 @@ import org.onlab.onos.net.device.DeviceEvent; ...@@ -36,6 +39,8 @@ import org.onlab.onos.net.device.DeviceEvent;
36 import org.onlab.onos.net.device.DeviceListener; 39 import org.onlab.onos.net.device.DeviceListener;
37 import org.onlab.onos.net.flow.DefaultTrafficSelector; 40 import org.onlab.onos.net.flow.DefaultTrafficSelector;
38 import org.onlab.onos.net.flow.DefaultTrafficTreatment; 41 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
42 +import org.onlab.onos.net.flow.FlowRuleEvent;
43 +import org.onlab.onos.net.flow.FlowRuleListener;
39 import org.onlab.onos.net.flow.TrafficSelector; 44 import org.onlab.onos.net.flow.TrafficSelector;
40 import org.onlab.onos.net.flow.TrafficTreatment; 45 import org.onlab.onos.net.flow.TrafficTreatment;
41 import org.onlab.onos.net.host.HostEvent; 46 import org.onlab.onos.net.host.HostEvent;
...@@ -84,8 +89,7 @@ public class TopologyViewWebSocket ...@@ -84,8 +89,7 @@ public class TopologyViewWebSocket
84 89
85 private static final String APP_ID = "org.onlab.onos.gui"; 90 private static final String APP_ID = "org.onlab.onos.gui";
86 91
87 - private static final long SUMMARY_FREQUENCY_SEC = 3000; 92 + private static final long TRAFFIC_FREQUENCY_SEC = 2000;
88 - private static final long TRAFFIC_FREQUENCY_SEC = 1500;
89 93
90 private static final Comparator<? super ControllerNode> NODE_COMPARATOR = 94 private static final Comparator<? super ControllerNode> NODE_COMPARATOR =
91 new Comparator<ControllerNode>() { 95 new Comparator<ControllerNode>() {
...@@ -95,6 +99,13 @@ public class TopologyViewWebSocket ...@@ -95,6 +99,13 @@ public class TopologyViewWebSocket
95 } 99 }
96 }; 100 };
97 101
102 +
103 + private final Timer timer = new Timer("topology-view");
104 +
105 + private static final int MAX_EVENTS = 500;
106 + private static final int MAX_BATCH_MS = 1000;
107 + private static final int MAX_IDLE_MS = 500;
108 +
98 private final ApplicationId appId; 109 private final ApplicationId appId;
99 110
100 private Connection connection; 111 private Connection connection;
...@@ -106,16 +117,14 @@ public class TopologyViewWebSocket ...@@ -106,16 +117,14 @@ public class TopologyViewWebSocket
106 private final LinkListener linkListener = new InternalLinkListener(); 117 private final LinkListener linkListener = new InternalLinkListener();
107 private final HostListener hostListener = new InternalHostListener(); 118 private final HostListener hostListener = new InternalHostListener();
108 private final IntentListener intentListener = new InternalIntentListener(); 119 private final IntentListener intentListener = new InternalIntentListener();
120 + private final FlowRuleListener flowListener = new InternalFlowListener();
109 121
110 - // Timers and objects being monitored 122 + private final EventAccumulator eventAccummulator = new InternalEventAccummulator();
111 - private final Timer timer = new Timer("topology-view");
112 123
124 + private boolean summaryEnabled = true;
113 private TimerTask trafficTask; 125 private TimerTask trafficTask;
114 private ObjectNode trafficEvent; 126 private ObjectNode trafficEvent;
115 127
116 - private TimerTask summaryTask;
117 - private ObjectNode summaryEvent;
118 -
119 private long lastActive = System.currentTimeMillis(); 128 private long lastActive = System.currentTimeMillis();
120 private boolean listenersRemoved = false; 129 private boolean listenersRemoved = false;
121 130
...@@ -128,7 +137,6 @@ public class TopologyViewWebSocket ...@@ -128,7 +137,6 @@ public class TopologyViewWebSocket
128 */ 137 */
129 public TopologyViewWebSocket(ServiceDirectory directory) { 138 public TopologyViewWebSocket(ServiceDirectory directory) {
130 super(directory); 139 super(directory);
131 -
132 intentFilter = new TopologyViewIntentFilter(intentService, deviceService, 140 intentFilter = new TopologyViewIntentFilter(intentService, deviceService,
133 hostService, linkService); 141 hostService, linkService);
134 appId = directory.get(CoreService.class).registerApplication(APP_ID); 142 appId = directory.get(CoreService.class).registerApplication(APP_ID);
...@@ -431,21 +439,13 @@ public class TopologyViewWebSocket ...@@ -431,21 +439,13 @@ public class TopologyViewWebSocket
431 439
432 // Subscribes for summary messages. 440 // Subscribes for summary messages.
433 private synchronized void requestSummary(ObjectNode event) { 441 private synchronized void requestSummary(ObjectNode event) {
434 - if (summaryTask == null) { 442 + summaryEnabled = true;
435 - summaryEvent = event;
436 - summaryTask = new SummaryMonitor();
437 - timer.schedule(summaryTask, SUMMARY_FREQUENCY_SEC, SUMMARY_FREQUENCY_SEC);
438 - }
439 sendMessage(summmaryMessage(number(event, "sid"))); 443 sendMessage(summmaryMessage(number(event, "sid")));
440 } 444 }
441 445
442 // Cancels sending summary messages. 446 // Cancels sending summary messages.
443 private synchronized void cancelSummary(ObjectNode event) { 447 private synchronized void cancelSummary(ObjectNode event) {
444 - if (summaryTask != null) { 448 + summaryEnabled = false;
445 - summaryTask.cancel();
446 - summaryTask = null;
447 - summaryEvent = null;
448 - }
449 } 449 }
450 450
451 451
...@@ -457,6 +457,7 @@ public class TopologyViewWebSocket ...@@ -457,6 +457,7 @@ public class TopologyViewWebSocket
457 linkService.addListener(linkListener); 457 linkService.addListener(linkListener);
458 hostService.addListener(hostListener); 458 hostService.addListener(hostListener);
459 intentService.addListener(intentListener); 459 intentService.addListener(intentListener);
460 + flowService.addListener(flowListener);
460 } 461 }
461 462
462 // Removes all internal listeners. 463 // Removes all internal listeners.
...@@ -469,6 +470,7 @@ public class TopologyViewWebSocket ...@@ -469,6 +470,7 @@ public class TopologyViewWebSocket
469 linkService.removeListener(linkListener); 470 linkService.removeListener(linkListener);
470 hostService.removeListener(hostListener); 471 hostService.removeListener(hostListener);
471 intentService.removeListener(intentListener); 472 intentService.removeListener(intentListener);
473 + flowService.removeListener(flowListener);
472 } 474 }
473 } 475 }
474 476
...@@ -495,6 +497,7 @@ public class TopologyViewWebSocket ...@@ -495,6 +497,7 @@ public class TopologyViewWebSocket
495 @Override 497 @Override
496 public void event(DeviceEvent event) { 498 public void event(DeviceEvent event) {
497 sendMessage(deviceMessage(event)); 499 sendMessage(deviceMessage(event));
500 + eventAccummulator.add(event);
498 } 501 }
499 } 502 }
500 503
...@@ -503,6 +506,7 @@ public class TopologyViewWebSocket ...@@ -503,6 +506,7 @@ public class TopologyViewWebSocket
503 @Override 506 @Override
504 public void event(LinkEvent event) { 507 public void event(LinkEvent event) {
505 sendMessage(linkMessage(event)); 508 sendMessage(linkMessage(event));
509 + eventAccummulator.add(event);
506 } 510 }
507 } 511 }
508 512
...@@ -511,6 +515,7 @@ public class TopologyViewWebSocket ...@@ -511,6 +515,7 @@ public class TopologyViewWebSocket
511 @Override 515 @Override
512 public void event(HostEvent event) { 516 public void event(HostEvent event) {
513 sendMessage(hostMessage(event)); 517 sendMessage(hostMessage(event));
518 + eventAccummulator.add(event);
514 } 519 }
515 } 520 }
516 521
...@@ -521,33 +526,55 @@ public class TopologyViewWebSocket ...@@ -521,33 +526,55 @@ public class TopologyViewWebSocket
521 if (trafficEvent != null) { 526 if (trafficEvent != null) {
522 requestTraffic(trafficEvent); 527 requestTraffic(trafficEvent);
523 } 528 }
529 + eventAccummulator.add(event);
530 + }
531 + }
532 +
533 + // Intent event listener.
534 + private class InternalFlowListener implements FlowRuleListener {
535 + @Override
536 + public void event(FlowRuleEvent event) {
537 + eventAccummulator.add(event);
524 } 538 }
525 } 539 }
526 540
527 private class TrafficMonitor extends TimerTask { 541 private class TrafficMonitor extends TimerTask {
528 @Override 542 @Override
529 public void run() { 543 public void run() {
530 - if (trafficEvent != null) { 544 + try {
531 - String type = string(trafficEvent, "event", "unknown"); 545 + if (trafficEvent != null) {
532 - if (type.equals("requestAllTraffic")) { 546 + String type = string(trafficEvent, "event", "unknown");
533 - requestAllTraffic(trafficEvent); 547 + if (type.equals("requestAllTraffic")) {
534 - } else if (type.equals("requestDeviceLinkFlows")) { 548 + requestAllTraffic(trafficEvent);
535 - requestDeviceLinkFlows(trafficEvent); 549 + } else if (type.equals("requestDeviceLinkFlows")) {
536 - } else { 550 + requestDeviceLinkFlows(trafficEvent);
537 - requestTraffic(trafficEvent); 551 + } else {
552 + requestTraffic(trafficEvent);
553 + }
538 } 554 }
555 + } catch (Exception e) {
556 + log.warn("Unable to handle traffic request due to {}", e.getMessage());
539 } 557 }
540 } 558 }
541 } 559 }
542 560
543 - private class SummaryMonitor extends TimerTask { 561 + // Accummulates events to drive methodic update of the summary pane.
562 + private class InternalEventAccummulator extends AbstractEventAccumulator {
563 + protected InternalEventAccummulator() {
564 + super(new Timer("topo-summary"), MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
565 + }
566 +
544 @Override 567 @Override
545 - public void run() { 568 + public void processEvents(List<Event> events) {
546 - if (summaryEvent != null) { 569 + try {
547 - requestSummary(summaryEvent); 570 + if (summaryEnabled) {
571 + sendMessage(summmaryMessage(0));
572 + }
573 + } catch (Exception e) {
574 + log.warn("Unable to handle summary request due to {}", e.getMessage());
548 } 575 }
576 +
549 } 577 }
550 } 578 }
551 -
552 } 579 }
553 580
......
...@@ -356,6 +356,9 @@ ...@@ -356,6 +356,9 @@
356 hideInstances(); 356 hideInstances();
357 } else if (summaryPane.isVisible()) { 357 } else if (summaryPane.isVisible()) {
358 cancelSummary(); 358 cancelSummary();
359 + stopAntTimer();
360 + } else {
361 + hoverMode = hoverModeFlows;
359 } 362 }
360 } 363 }
361 364
......