blob: 770f36832ec5b6dd7217db53572dc11e67666b70 [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
26import java.util.List;
27import java.util.Timer;
28import java.util.concurrent.ExecutorService;
29
30import static java.util.concurrent.Executors.newFixedThreadPool;
31import static org.onlab.onos.net.device.DeviceEvent.Type.*;
32import static org.onlab.util.Tools.namedThreads;
33import static org.slf4j.LoggerFactory.getLogger;
34
35/**
tom578ebdc2014-09-11 11:12:51 -070036 * Default implementation of a network topology provider that feeds off
37 * device and link subsystem events to trigger assembly and computation of
38 * new topology snapshots.
tomcbff9392014-09-10 00:45:23 -070039 */
40@Component(immediate = true)
tom97937552014-09-11 10:48:42 -070041public class DefaultTopologyProvider extends AbstractProvider
tomcbff9392014-09-10 00:45:23 -070042 implements TopologyProvider {
43
44 // TODO: make these configurable
45 private static final int MAX_EVENTS = 100;
46 private static final int MAX_IDLE_MS = 50;
47 private static final int MAX_BATCH_MS = 200;
48 private static final int MAX_THREADS = 8;
49
tom025e09f2014-09-15 15:29:24 -070050 // FIXME: Replace with a system-wide timer instance;
51 // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt
tomcbff9392014-09-10 00:45:23 -070052 private static final Timer TIMER = new Timer();
53
54 private final Logger log = getLogger(getClass());
55
56 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
57 protected TopologyProviderRegistry providerRegistry;
58
59 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
60 protected DeviceService deviceService;
61
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected LinkService linkService;
64
65 private volatile boolean isStarted = false;
66
67 private TopologyProviderService providerService;
68 private DeviceListener deviceListener = new InnerDeviceListener();
69 private LinkListener linkListener = new InnerLinkListener();
70
71 private EventAccumulator accumulator;
72 private ExecutorService executor;
73
74 /**
75 * Creates a provider with the supplier identifier.
76 */
tom97937552014-09-11 10:48:42 -070077 public DefaultTopologyProvider() {
tom7e02cda2014-09-18 12:05:46 -070078 super(new ProviderId("core", "org.onlab.onos.provider.topology"));
tomcbff9392014-09-10 00:45:23 -070079 }
80
81 @Activate
82 public synchronized void activate() {
tom578ebdc2014-09-11 11:12:51 -070083 executor = newFixedThreadPool(MAX_THREADS, namedThreads("topo-build-%d"));
tomcbff9392014-09-10 00:45:23 -070084 accumulator = new TopologyChangeAccumulator();
85
86 providerService = providerRegistry.register(this);
87 deviceService.addListener(deviceListener);
88 linkService.addListener(linkListener);
89
90 isStarted = true;
91 triggerTopologyBuild(null);
92 log.info("Started");
93 }
94
95 @Deactivate
96 public synchronized void deactivate() {
tome52ce702014-09-11 00:12:54 -070097 isStarted = false;
98
tomcbff9392014-09-10 00:45:23 -070099 deviceService.removeListener(deviceListener);
100 linkService.removeListener(linkListener);
101 providerRegistry.unregister(this);
102 providerService = null;
103
104 executor.shutdownNow();
105 executor = null;
106
tomcbff9392014-09-10 00:45:23 -0700107 log.info("Stopped");
108 }
109
110 /**
111 * Triggers assembly of topology data citing the specified events as the
112 * reason.
113 *
114 * @param reasons events which triggered the topology change
115 */
tome52ce702014-09-11 00:12:54 -0700116 private synchronized void triggerTopologyBuild(List<Event> reasons) {
tom97937552014-09-11 10:48:42 -0700117 if (executor != null) {
118 executor.execute(new TopologyBuilderTask(reasons));
119 }
tomcbff9392014-09-10 00:45:23 -0700120 }
121
122 // Builds the topology using the latest device and link information
123 // and citing the specified events as reasons for the change.
124 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700125 if (isStarted) {
tom97937552014-09-11 10:48:42 -0700126 GraphDescription desc =
127 new DefaultGraphDescription(System.nanoTime(),
128 deviceService.getDevices(),
129 linkService.getLinks());
tomcbff9392014-09-10 00:45:23 -0700130 providerService.topologyChanged(desc, reasons);
131 }
132 }
133
134 // Callback for device events
135 private class InnerDeviceListener implements DeviceListener {
136 @Override
137 public void event(DeviceEvent event) {
138 DeviceEvent.Type type = event.type();
139 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
140 type == DEVICE_AVAILABILITY_CHANGED) {
141 accumulator.add(event);
142 }
143 }
144 }
145
146 // Callback for link events
147 private class InnerLinkListener implements LinkListener {
148 @Override
149 public void event(LinkEvent event) {
150 accumulator.add(event);
151 }
152 }
153
154 // Event accumulator for paced triggering of topology assembly.
155 private class TopologyChangeAccumulator
156 extends AbstractEventAccumulator implements EventAccumulator {
157
158 TopologyChangeAccumulator() {
159 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
160 }
161
162 @Override
163 public void processEvents(List<Event> events) {
164 triggerTopologyBuild(events);
165 }
166
167 }
168
169 // Task for building topology data in a separate thread.
170 private class TopologyBuilderTask implements Runnable {
171 private final List<Event> reasons;
172
173 public TopologyBuilderTask(List<Event> reasons) {
174 this.reasons = reasons;
175 }
176
177 @Override
178 public void run() {
179 buildTopology(reasons);
180 }
181 }
182
183}