blob: 9631c66e265f9dc103eb769439062136ec2cde03 [file] [log] [blame]
tombe988312014-09-19 18:38:47 -07001package org.onlab.onos.net.topology.impl;
tomcbff9392014-09-10 00:45:23 -07002
3import org.apache.felix.scr.annotations.Activate;
4import org.apache.felix.scr.annotations.Component;
5import org.apache.felix.scr.annotations.Deactivate;
6import org.apache.felix.scr.annotations.Reference;
7import org.apache.felix.scr.annotations.ReferenceCardinality;
8import org.onlab.onos.event.AbstractEventAccumulator;
9import org.onlab.onos.event.Event;
10import org.onlab.onos.event.EventAccumulator;
11import org.onlab.onos.net.device.DeviceEvent;
12import org.onlab.onos.net.device.DeviceListener;
13import org.onlab.onos.net.device.DeviceService;
14import org.onlab.onos.net.link.LinkEvent;
15import org.onlab.onos.net.link.LinkListener;
16import org.onlab.onos.net.link.LinkService;
17import org.onlab.onos.net.provider.AbstractProvider;
18import org.onlab.onos.net.provider.ProviderId;
tombe988312014-09-19 18:38:47 -070019import org.onlab.onos.net.topology.DefaultGraphDescription;
tom97937552014-09-11 10:48:42 -070020import org.onlab.onos.net.topology.GraphDescription;
tomcbff9392014-09-10 00:45:23 -070021import org.onlab.onos.net.topology.TopologyProvider;
22import org.onlab.onos.net.topology.TopologyProviderRegistry;
23import org.onlab.onos.net.topology.TopologyProviderService;
24import org.slf4j.Logger;
25
Pavlin Radoslavova0e47542014-10-17 19:22:17 -070026import java.util.Collections;
tomcbff9392014-09-10 00:45:23 -070027import java.util.List;
28import java.util.Timer;
29import java.util.concurrent.ExecutorService;
30
31import static java.util.concurrent.Executors.newFixedThreadPool;
32import static org.onlab.onos.net.device.DeviceEvent.Type.*;
33import static org.onlab.util.Tools.namedThreads;
34import static org.slf4j.LoggerFactory.getLogger;
35
36/**
tom578ebdc2014-09-11 11:12:51 -070037 * Default implementation of a network topology provider that feeds off
38 * device and link subsystem events to trigger assembly and computation of
39 * new topology snapshots.
tomcbff9392014-09-10 00:45:23 -070040 */
41@Component(immediate = true)
tom97937552014-09-11 10:48:42 -070042public class DefaultTopologyProvider extends AbstractProvider
tomcbff9392014-09-10 00:45:23 -070043 implements TopologyProvider {
44
45 // TODO: make these configurable
46 private static final int MAX_EVENTS = 100;
47 private static final int MAX_IDLE_MS = 50;
48 private static final int MAX_BATCH_MS = 200;
49 private static final int MAX_THREADS = 8;
50
tom025e09f2014-09-15 15:29:24 -070051 // FIXME: Replace with a system-wide timer instance;
52 // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt
tomcbff9392014-09-10 00:45:23 -070053 private static final Timer TIMER = new Timer();
54
55 private final Logger log = getLogger(getClass());
56
57 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 protected TopologyProviderRegistry providerRegistry;
59
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 protected DeviceService deviceService;
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected LinkService linkService;
65
66 private volatile boolean isStarted = false;
67
68 private TopologyProviderService providerService;
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070069 private DeviceListener deviceListener = new InternalDeviceListener();
70 private LinkListener linkListener = new InternalLinkListener();
tomcbff9392014-09-10 00:45:23 -070071
72 private EventAccumulator accumulator;
73 private ExecutorService executor;
74
75 /**
76 * Creates a provider with the supplier identifier.
77 */
tom97937552014-09-11 10:48:42 -070078 public DefaultTopologyProvider() {
tom7e02cda2014-09-18 12:05:46 -070079 super(new ProviderId("core", "org.onlab.onos.provider.topology"));
tomcbff9392014-09-10 00:45:23 -070080 }
81
82 @Activate
83 public synchronized void activate() {
tom578ebdc2014-09-11 11:12:51 -070084 executor = newFixedThreadPool(MAX_THREADS, namedThreads("topo-build-%d"));
tomcbff9392014-09-10 00:45:23 -070085 accumulator = new TopologyChangeAccumulator();
86
87 providerService = providerRegistry.register(this);
88 deviceService.addListener(deviceListener);
89 linkService.addListener(linkListener);
90
91 isStarted = true;
Pavlin Radoslavova0e47542014-10-17 19:22:17 -070092 triggerTopologyBuild(Collections.<Event>emptyList());
tomcbff9392014-09-10 00:45:23 -070093 log.info("Started");
94 }
95
96 @Deactivate
97 public synchronized void deactivate() {
tome52ce702014-09-11 00:12:54 -070098 isStarted = false;
99
tomcbff9392014-09-10 00:45:23 -0700100 deviceService.removeListener(deviceListener);
101 linkService.removeListener(linkListener);
102 providerRegistry.unregister(this);
103 providerService = null;
104
105 executor.shutdownNow();
106 executor = null;
107
tomcbff9392014-09-10 00:45:23 -0700108 log.info("Stopped");
109 }
110
111 /**
112 * Triggers assembly of topology data citing the specified events as the
113 * reason.
114 *
115 * @param reasons events which triggered the topology change
116 */
tome52ce702014-09-11 00:12:54 -0700117 private synchronized void triggerTopologyBuild(List<Event> reasons) {
tom97937552014-09-11 10:48:42 -0700118 if (executor != null) {
119 executor.execute(new TopologyBuilderTask(reasons));
120 }
tomcbff9392014-09-10 00:45:23 -0700121 }
122
123 // Builds the topology using the latest device and link information
124 // and citing the specified events as reasons for the change.
125 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700126 if (isStarted) {
tom97937552014-09-11 10:48:42 -0700127 GraphDescription desc =
128 new DefaultGraphDescription(System.nanoTime(),
129 deviceService.getDevices(),
130 linkService.getLinks());
tomcbff9392014-09-10 00:45:23 -0700131 providerService.topologyChanged(desc, reasons);
132 }
133 }
134
135 // Callback for device events
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700136 private class InternalDeviceListener implements DeviceListener {
tomcbff9392014-09-10 00:45:23 -0700137 @Override
138 public void event(DeviceEvent event) {
139 DeviceEvent.Type type = event.type();
140 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
141 type == DEVICE_AVAILABILITY_CHANGED) {
142 accumulator.add(event);
143 }
144 }
145 }
146
147 // Callback for link events
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700148 private class InternalLinkListener implements LinkListener {
tomcbff9392014-09-10 00:45:23 -0700149 @Override
150 public void event(LinkEvent event) {
151 accumulator.add(event);
152 }
153 }
154
155 // Event accumulator for paced triggering of topology assembly.
156 private class TopologyChangeAccumulator
157 extends AbstractEventAccumulator implements EventAccumulator {
158
159 TopologyChangeAccumulator() {
160 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
161 }
162
163 @Override
164 public void processEvents(List<Event> events) {
165 triggerTopologyBuild(events);
166 }
167
168 }
169
170 // Task for building topology data in a separate thread.
171 private class TopologyBuilderTask implements Runnable {
172 private final List<Event> reasons;
173
174 public TopologyBuilderTask(List<Event> reasons) {
175 this.reasons = reasons;
176 }
177
178 @Override
179 public void run() {
180 buildTopology(reasons);
181 }
182 }
183
184}