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