blob: f49f7d30b30df49d0aefd3d4a41aee96458a58c8 [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/**
35 * Simple implementation of a network topology provider/computor.
36 */
37@Component(immediate = true)
tom97937552014-09-11 10:48:42 -070038public class DefaultTopologyProvider extends AbstractProvider
tomcbff9392014-09-10 00:45:23 -070039 implements TopologyProvider {
40
41 // TODO: make these configurable
42 private static final int MAX_EVENTS = 100;
43 private static final int MAX_IDLE_MS = 50;
44 private static final int MAX_BATCH_MS = 200;
45 private static final int MAX_THREADS = 8;
46
47 // FIXME: Replace with a system-wide timer instance
48 private static final Timer TIMER = new Timer();
49
50 private final Logger log = getLogger(getClass());
51
52 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected TopologyProviderRegistry providerRegistry;
54
55 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected DeviceService deviceService;
57
58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected LinkService linkService;
60
61 private volatile boolean isStarted = false;
62
63 private TopologyProviderService providerService;
64 private DeviceListener deviceListener = new InnerDeviceListener();
65 private LinkListener linkListener = new InnerLinkListener();
66
67 private EventAccumulator accumulator;
68 private ExecutorService executor;
69
70 /**
71 * Creates a provider with the supplier identifier.
72 */
tom97937552014-09-11 10:48:42 -070073 public DefaultTopologyProvider() {
tomcbff9392014-09-10 00:45:23 -070074 super(new ProviderId("org.onlab.onos.provider.topology"));
75 }
76
77 @Activate
78 public synchronized void activate() {
79 executor = newFixedThreadPool(MAX_THREADS, namedThreads("topo-compute-%d"));
80 accumulator = new TopologyChangeAccumulator();
81
82 providerService = providerRegistry.register(this);
83 deviceService.addListener(deviceListener);
84 linkService.addListener(linkListener);
85
86 isStarted = true;
87 triggerTopologyBuild(null);
88 log.info("Started");
89 }
90
91 @Deactivate
92 public synchronized void deactivate() {
tome52ce702014-09-11 00:12:54 -070093 isStarted = false;
94
tomcbff9392014-09-10 00:45:23 -070095 deviceService.removeListener(deviceListener);
96 linkService.removeListener(linkListener);
97 providerRegistry.unregister(this);
98 providerService = null;
99
100 executor.shutdownNow();
101 executor = null;
102
tomcbff9392014-09-10 00:45:23 -0700103 log.info("Stopped");
104 }
105
106 /**
107 * Triggers assembly of topology data citing the specified events as the
108 * reason.
109 *
110 * @param reasons events which triggered the topology change
111 */
tome52ce702014-09-11 00:12:54 -0700112 private synchronized void triggerTopologyBuild(List<Event> reasons) {
tom97937552014-09-11 10:48:42 -0700113 if (executor != null) {
114 executor.execute(new TopologyBuilderTask(reasons));
115 }
tomcbff9392014-09-10 00:45:23 -0700116 }
117
118 // Builds the topology using the latest device and link information
119 // and citing the specified events as reasons for the change.
120 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700121 if (isStarted) {
tom97937552014-09-11 10:48:42 -0700122 GraphDescription desc =
123 new DefaultGraphDescription(System.nanoTime(),
124 deviceService.getDevices(),
125 linkService.getLinks());
tomcbff9392014-09-10 00:45:23 -0700126 providerService.topologyChanged(desc, reasons);
127 }
128 }
129
130 // Callback for device events
131 private class InnerDeviceListener implements DeviceListener {
132 @Override
133 public void event(DeviceEvent event) {
134 DeviceEvent.Type type = event.type();
135 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
136 type == DEVICE_AVAILABILITY_CHANGED) {
137 accumulator.add(event);
138 }
139 }
140 }
141
142 // Callback for link events
143 private class InnerLinkListener implements LinkListener {
144 @Override
145 public void event(LinkEvent event) {
146 accumulator.add(event);
147 }
148 }
149
150 // Event accumulator for paced triggering of topology assembly.
151 private class TopologyChangeAccumulator
152 extends AbstractEventAccumulator implements EventAccumulator {
153
154 TopologyChangeAccumulator() {
155 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
156 }
157
158 @Override
159 public void processEvents(List<Event> events) {
160 triggerTopologyBuild(events);
161 }
162
163 }
164
165 // Task for building topology data in a separate thread.
166 private class TopologyBuilderTask implements Runnable {
167 private final List<Event> reasons;
168
169 public TopologyBuilderTask(List<Event> reasons) {
170 this.reasons = reasons;
171 }
172
173 @Override
174 public void run() {
175 buildTopology(reasons);
176 }
177 }
178
179}