blob: 6b0e0369544c9a7f3cac5773407c8af91c99943f [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
49 // FIXME: Replace with a system-wide timer instance
50 private static final Timer TIMER = new Timer();
51
52 private final Logger log = getLogger(getClass());
53
54 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
55 protected TopologyProviderRegistry providerRegistry;
56
57 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 protected DeviceService deviceService;
59
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 protected LinkService linkService;
62
63 private volatile boolean isStarted = false;
64
65 private TopologyProviderService providerService;
66 private DeviceListener deviceListener = new InnerDeviceListener();
67 private LinkListener linkListener = new InnerLinkListener();
68
69 private EventAccumulator accumulator;
70 private ExecutorService executor;
71
72 /**
73 * Creates a provider with the supplier identifier.
74 */
tom97937552014-09-11 10:48:42 -070075 public DefaultTopologyProvider() {
tomcbff9392014-09-10 00:45:23 -070076 super(new ProviderId("org.onlab.onos.provider.topology"));
77 }
78
79 @Activate
80 public synchronized void activate() {
tom578ebdc2014-09-11 11:12:51 -070081 executor = newFixedThreadPool(MAX_THREADS, namedThreads("topo-build-%d"));
tomcbff9392014-09-10 00:45:23 -070082 accumulator = new TopologyChangeAccumulator();
83
84 providerService = providerRegistry.register(this);
85 deviceService.addListener(deviceListener);
86 linkService.addListener(linkListener);
87
88 isStarted = true;
89 triggerTopologyBuild(null);
90 log.info("Started");
91 }
92
93 @Deactivate
94 public synchronized void deactivate() {
tome52ce702014-09-11 00:12:54 -070095 isStarted = false;
96
tomcbff9392014-09-10 00:45:23 -070097 deviceService.removeListener(deviceListener);
98 linkService.removeListener(linkListener);
99 providerRegistry.unregister(this);
100 providerService = null;
101
102 executor.shutdownNow();
103 executor = null;
104
tomcbff9392014-09-10 00:45:23 -0700105 log.info("Stopped");
106 }
107
108 /**
109 * Triggers assembly of topology data citing the specified events as the
110 * reason.
111 *
112 * @param reasons events which triggered the topology change
113 */
tome52ce702014-09-11 00:12:54 -0700114 private synchronized void triggerTopologyBuild(List<Event> reasons) {
tom97937552014-09-11 10:48:42 -0700115 if (executor != null) {
116 executor.execute(new TopologyBuilderTask(reasons));
117 }
tomcbff9392014-09-10 00:45:23 -0700118 }
119
120 // Builds the topology using the latest device and link information
121 // and citing the specified events as reasons for the change.
122 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700123 if (isStarted) {
tom97937552014-09-11 10:48:42 -0700124 GraphDescription desc =
125 new DefaultGraphDescription(System.nanoTime(),
126 deviceService.getDevices(),
127 linkService.getLinks());
tomcbff9392014-09-10 00:45:23 -0700128 providerService.topologyChanged(desc, reasons);
129 }
130 }
131
132 // Callback for device events
133 private class InnerDeviceListener implements DeviceListener {
134 @Override
135 public void event(DeviceEvent event) {
136 DeviceEvent.Type type = event.type();
137 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
138 type == DEVICE_AVAILABILITY_CHANGED) {
139 accumulator.add(event);
140 }
141 }
142 }
143
144 // Callback for link events
145 private class InnerLinkListener implements LinkListener {
146 @Override
147 public void event(LinkEvent event) {
148 accumulator.add(event);
149 }
150 }
151
152 // Event accumulator for paced triggering of topology assembly.
153 private class TopologyChangeAccumulator
154 extends AbstractEventAccumulator implements EventAccumulator {
155
156 TopologyChangeAccumulator() {
157 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
158 }
159
160 @Override
161 public void processEvents(List<Event> events) {
162 triggerTopologyBuild(events);
163 }
164
165 }
166
167 // Task for building topology data in a separate thread.
168 private class TopologyBuilderTask implements Runnable {
169 private final List<Event> reasons;
170
171 public TopologyBuilderTask(List<Event> reasons) {
172 this.reasons = reasons;
173 }
174
175 @Override
176 public void run() {
177 buildTopology(reasons);
178 }
179 }
180
181}