blob: 777a0e470679930c8e4b95435f58443e5b6a1256 [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() {
93 deviceService.removeListener(deviceListener);
94 linkService.removeListener(linkListener);
95 providerRegistry.unregister(this);
96 providerService = null;
97
98 executor.shutdownNow();
99 executor = null;
100
101 isStarted = false;
102 log.info("Stopped");
103 }
104
105 /**
106 * Triggers assembly of topology data citing the specified events as the
107 * reason.
108 *
109 * @param reasons events which triggered the topology change
110 */
111 private void triggerTopologyBuild(List<Event> reasons) {
112 executor.execute(new TopologyBuilderTask(reasons));
113 }
114
115 // Builds the topology using the latest device and link information
116 // and citing the specified events as reasons for the change.
117 private void buildTopology(List<Event> reasons) {
tomcbff9392014-09-10 00:45:23 -0700118 if (isStarted) {
119 TopologyDescription desc =
120 new DefaultTopologyDescription(System.nanoTime(),
121 deviceService.getDevices(),
122 linkService.getLinks());
123 providerService.topologyChanged(desc, reasons);
124 }
125 }
126
127 // Callback for device events
128 private class InnerDeviceListener implements DeviceListener {
129 @Override
130 public void event(DeviceEvent event) {
131 DeviceEvent.Type type = event.type();
132 if (type == DEVICE_ADDED || type == DEVICE_REMOVED ||
133 type == DEVICE_AVAILABILITY_CHANGED) {
134 accumulator.add(event);
135 }
136 }
137 }
138
139 // Callback for link events
140 private class InnerLinkListener implements LinkListener {
141 @Override
142 public void event(LinkEvent event) {
143 accumulator.add(event);
144 }
145 }
146
147 // Event accumulator for paced triggering of topology assembly.
148 private class TopologyChangeAccumulator
149 extends AbstractEventAccumulator implements EventAccumulator {
150
151 TopologyChangeAccumulator() {
152 super(TIMER, MAX_EVENTS, MAX_BATCH_MS, MAX_IDLE_MS);
153 }
154
155 @Override
156 public void processEvents(List<Event> events) {
157 triggerTopologyBuild(events);
158 }
159
160 }
161
162 // Task for building topology data in a separate thread.
163 private class TopologyBuilderTask implements Runnable {
164 private final List<Event> reasons;
165
166 public TopologyBuilderTask(List<Event> reasons) {
167 this.reasons = reasons;
168 }
169
170 @Override
171 public void run() {
172 buildTopology(reasons);
173 }
174 }
175
176}