blob: 5955c329212644218091114d62ad2be7427c7ae0 [file] [log] [blame]
tom8bf2e6b2014-09-10 20:53:54 -07001package org.onlab.onos.net.trivial.topology.provider.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;
19import org.onlab.onos.net.topology.TopologyDescription;
20import 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)
38public class SimpleTopologyProvider extends AbstractProvider
39 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 */
73 public SimpleTopologyProvider() {
74 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) {
tomcbff9392014-09-10 00:45:23 -0700113 executor.execute(new TopologyBuilderTask(reasons));
114 }
115
116 // Builds the topology using the latest device and link information
117 // and citing the specified events as reasons for the change.
118 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700119 if (isStarted) {
120 TopologyDescription desc =
121 new DefaultTopologyDescription(System.nanoTime(),
122 deviceService.getDevices(),
123 linkService.getLinks());
124 providerService.topologyChanged(desc, reasons);
125 }
126 }
127
128 // Callback for device events
129 private class InnerDeviceListener implements DeviceListener {
130 @Override
131 public void event(DeviceEvent event) {
132 DeviceEvent.Type type = event.type();
133 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
134 type == DEVICE_AVAILABILITY_CHANGED) {
135 accumulator.add(event);
136 }
137 }
138 }
139
140 // Callback for link events
141 private class InnerLinkListener implements LinkListener {
142 @Override
143 public void event(LinkEvent event) {
144 accumulator.add(event);
145 }
146 }
147
148 // Event accumulator for paced triggering of topology assembly.
149 private class TopologyChangeAccumulator
150 extends AbstractEventAccumulator implements EventAccumulator {
151
152 TopologyChangeAccumulator() {
153 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
154 }
155
156 @Override
157 public void processEvents(List<Event> events) {
158 triggerTopologyBuild(events);
159 }
160
161 }
162
163 // Task for building topology data in a separate thread.
164 private class TopologyBuilderTask implements Runnable {
165 private final List<Event> reasons;
166
167 public TopologyBuilderTask(List<Event> reasons) {
168 this.reasons = reasons;
169 }
170
171 @Override
172 public void run() {
173 buildTopology(reasons);
174 }
175 }
176
177}