blob: 0efd08ba2616cc1f9debf8cf8468c00c0375e528 [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;
Thomas Vachuska0e752bd2014-10-22 22:33:41 -07008import org.apache.felix.scr.annotations.Service;
tomcbff9392014-09-10 00:45:23 -07009import org.onlab.onos.event.AbstractEventAccumulator;
10import org.onlab.onos.event.Event;
11import org.onlab.onos.event.EventAccumulator;
12import org.onlab.onos.net.device.DeviceEvent;
13import org.onlab.onos.net.device.DeviceListener;
14import org.onlab.onos.net.device.DeviceService;
15import org.onlab.onos.net.link.LinkEvent;
16import org.onlab.onos.net.link.LinkListener;
17import org.onlab.onos.net.link.LinkService;
18import org.onlab.onos.net.provider.AbstractProvider;
19import org.onlab.onos.net.provider.ProviderId;
tombe988312014-09-19 18:38:47 -070020import org.onlab.onos.net.topology.DefaultGraphDescription;
tom97937552014-09-11 10:48:42 -070021import org.onlab.onos.net.topology.GraphDescription;
tomcbff9392014-09-10 00:45:23 -070022import org.onlab.onos.net.topology.TopologyProvider;
23import org.onlab.onos.net.topology.TopologyProviderRegistry;
24import org.onlab.onos.net.topology.TopologyProviderService;
25import org.slf4j.Logger;
26
Pavlin Radoslavova0e47542014-10-17 19:22:17 -070027import java.util.Collections;
tomcbff9392014-09-10 00:45:23 -070028import java.util.List;
29import java.util.Timer;
30import java.util.concurrent.ExecutorService;
31
32import static java.util.concurrent.Executors.newFixedThreadPool;
33import static org.onlab.onos.net.device.DeviceEvent.Type.*;
34import static org.onlab.util.Tools.namedThreads;
35import static org.slf4j.LoggerFactory.getLogger;
36
37/**
tom578ebdc2014-09-11 11:12:51 -070038 * Default implementation of a network topology provider that feeds off
39 * device and link subsystem events to trigger assembly and computation of
40 * new topology snapshots.
tomcbff9392014-09-10 00:45:23 -070041 */
42@Component(immediate = true)
Thomas Vachuska0e752bd2014-10-22 22:33:41 -070043@Service
tom97937552014-09-11 10:48:42 -070044public class DefaultTopologyProvider extends AbstractProvider
tomcbff9392014-09-10 00:45:23 -070045 implements TopologyProvider {
46
47 // TODO: make these configurable
48 private static final int MAX_EVENTS = 100;
49 private static final int MAX_IDLE_MS = 50;
50 private static final int MAX_BATCH_MS = 200;
51 private static final int MAX_THREADS = 8;
52
tom025e09f2014-09-15 15:29:24 -070053 // FIXME: Replace with a system-wide timer instance;
54 // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt
tomcbff9392014-09-10 00:45:23 -070055 private static final Timer TIMER = new Timer();
56
57 private final Logger log = getLogger(getClass());
58
59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 protected TopologyProviderRegistry providerRegistry;
61
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected DeviceService deviceService;
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected LinkService linkService;
67
68 private volatile boolean isStarted = false;
69
70 private TopologyProviderService providerService;
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -070071 private DeviceListener deviceListener = new InternalDeviceListener();
72 private LinkListener linkListener = new InternalLinkListener();
tomcbff9392014-09-10 00:45:23 -070073
74 private EventAccumulator accumulator;
75 private ExecutorService executor;
76
77 /**
78 * Creates a provider with the supplier identifier.
79 */
tom97937552014-09-11 10:48:42 -070080 public DefaultTopologyProvider() {
tom7e02cda2014-09-18 12:05:46 -070081 super(new ProviderId("core", "org.onlab.onos.provider.topology"));
tomcbff9392014-09-10 00:45:23 -070082 }
83
84 @Activate
85 public synchronized void activate() {
tom578ebdc2014-09-11 11:12:51 -070086 executor = newFixedThreadPool(MAX_THREADS, namedThreads("topo-build-%d"));
tomcbff9392014-09-10 00:45:23 -070087 accumulator = new TopologyChangeAccumulator();
88
89 providerService = providerRegistry.register(this);
90 deviceService.addListener(deviceListener);
91 linkService.addListener(linkListener);
92
93 isStarted = true;
Thomas Vachuska0e752bd2014-10-22 22:33:41 -070094 triggerRecompute();
tomcbff9392014-09-10 00:45:23 -070095 log.info("Started");
96 }
97
98 @Deactivate
99 public synchronized void deactivate() {
tome52ce702014-09-11 00:12:54 -0700100 isStarted = false;
101
tomcbff9392014-09-10 00:45:23 -0700102 deviceService.removeListener(deviceListener);
103 linkService.removeListener(linkListener);
104 providerRegistry.unregister(this);
105 providerService = null;
106
107 executor.shutdownNow();
108 executor = null;
109
tomcbff9392014-09-10 00:45:23 -0700110 log.info("Stopped");
111 }
112
Thomas Vachuska0e752bd2014-10-22 22:33:41 -0700113 @Override
114 public void triggerRecompute() {
115 triggerTopologyBuild(Collections.<Event>emptyList());
116 }
117
tomcbff9392014-09-10 00:45:23 -0700118 /**
119 * Triggers assembly of topology data citing the specified events as the
120 * reason.
121 *
122 * @param reasons events which triggered the topology change
123 */
tome52ce702014-09-11 00:12:54 -0700124 private synchronized void triggerTopologyBuild(List<Event> reasons) {
tom97937552014-09-11 10:48:42 -0700125 if (executor != null) {
126 executor.execute(new TopologyBuilderTask(reasons));
127 }
tomcbff9392014-09-10 00:45:23 -0700128 }
129
130 // Builds the topology using the latest device and link information
131 // and citing the specified events as reasons for the change.
132 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700133 if (isStarted) {
tom97937552014-09-11 10:48:42 -0700134 GraphDescription desc =
135 new DefaultGraphDescription(System.nanoTime(),
136 deviceService.getDevices(),
137 linkService.getLinks());
tomcbff9392014-09-10 00:45:23 -0700138 providerService.topologyChanged(desc, reasons);
139 }
140 }
141
142 // Callback for device events
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700143 private class InternalDeviceListener implements DeviceListener {
tomcbff9392014-09-10 00:45:23 -0700144 @Override
145 public void event(DeviceEvent event) {
146 DeviceEvent.Type type = event.type();
147 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
148 type == DEVICE_AVAILABILITY_CHANGED) {
149 accumulator.add(event);
150 }
151 }
152 }
153
154 // Callback for link events
Ayaka Koshibe3de43ca2014-09-26 16:40:23 -0700155 private class InternalLinkListener implements LinkListener {
tomcbff9392014-09-10 00:45:23 -0700156 @Override
157 public void event(LinkEvent event) {
158 accumulator.add(event);
159 }
160 }
161
162 // Event accumulator for paced triggering of topology assembly.
163 private class TopologyChangeAccumulator
164 extends AbstractEventAccumulator implements EventAccumulator {
165
166 TopologyChangeAccumulator() {
167 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
168 }
169
170 @Override
171 public void processEvents(List<Event> events) {
172 triggerTopologyBuild(events);
173 }
174
175 }
176
177 // Task for building topology data in a separate thread.
178 private class TopologyBuilderTask implements Runnable {
179 private final List<Event> reasons;
180
181 public TopologyBuilderTask(List<Event> reasons) {
182 this.reasons = reasons;
183 }
184
185 @Override
186 public void run() {
Thomas Vachuska0e752bd2014-10-22 22:33:41 -0700187 try {
188 buildTopology(reasons);
189 } catch (Exception e) {
190 log.warn("Unable to compute topology due to: {}", e.getMessage());
191 }
tomcbff9392014-09-10 00:45:23 -0700192 }
193 }
194
195}