blob: fbd409f8dcad751caaa5b7fd67e7b2ef6fb114f8 [file] [log] [blame]
Jonathan Hart472062d2014-04-03 10:56:48 -07001package net.onrc.onos.core.topology;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08002
3import java.util.ArrayList;
4import java.util.Collection;
Jonathan Hart369875b2014-02-13 10:00:31 -08005import java.util.List;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08006import java.util.Map;
Jonathan Hart369875b2014-02-13 10:00:31 -08007import java.util.concurrent.TimeUnit;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -08008
9import net.floodlightcontroller.core.IFloodlightProviderService;
10import net.floodlightcontroller.core.IOFSwitch;
11import net.floodlightcontroller.core.module.FloodlightModuleContext;
12import net.floodlightcontroller.core.module.FloodlightModuleException;
13import net.floodlightcontroller.core.module.IFloodlightModule;
14import net.floodlightcontroller.core.module.IFloodlightService;
Jonathan Hart369875b2014-02-13 10:00:31 -080015import net.floodlightcontroller.core.util.SingletonTask;
16import net.floodlightcontroller.threadpool.IThreadPoolService;
Jonathan Hart23701d12014-04-03 10:45:48 -070017import net.onrc.onos.core.devicemanager.IOnosDeviceListener;
18import net.onrc.onos.core.devicemanager.IOnosDeviceService;
19import net.onrc.onos.core.devicemanager.OnosDevice;
20import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryListener;
21import net.onrc.onos.core.linkdiscovery.ILinkDiscoveryService;
Jonathan Hart51f6f5b2014-04-03 10:32:10 -070022import net.onrc.onos.core.main.IOFSwitchPortListener;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070023import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070024import net.onrc.onos.core.registry.IControllerRegistryService.ControlChangeCallback;
Jonathan Harta99ec672014-04-03 11:30:34 -070025import net.onrc.onos.core.registry.RegistryException;
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -070026import net.onrc.onos.core.util.Dpid;
Yuta HIGUCHI5c8cbeb2014-06-27 11:13:48 -070027import net.onrc.onos.core.util.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080028
29import org.openflow.protocol.OFPhysicalPort;
Jonathan Hart369875b2014-02-13 10:00:31 -080030import org.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080033
Jonathan Hart88770672014-04-02 18:08:30 -070034/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070035 * The TopologyPublisher subscribes to topology network events from the
36 * discovery modules. These events are reformatted and relayed to the in-memory
37 * topology instance.
Jonathan Hart88770672014-04-02 18:08:30 -070038 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070039public class TopologyPublisher implements /*IOFSwitchListener,*/
Ray Milkey269ffb92014-04-03 14:43:30 -070040 IOFSwitchPortListener,
41 ILinkDiscoveryListener,
42 IFloodlightModule,
43 IOnosDeviceListener {
Jonathan Hart88770672014-04-02 18:08:30 -070044 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070045 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080046
Jonathan Hart88770672014-04-02 18:08:30 -070047 private IFloodlightProviderService floodlightProvider;
48 private ILinkDiscoveryService linkDiscovery;
49 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070050 private ITopologyService topologyService;
Toshio Koide2f570c12014-02-06 16:55:32 -080051
Jonathan Hart88770672014-04-02 18:08:30 -070052 private IOnosDeviceService onosDeviceService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070053
Jonathan Harte37e4e22014-05-13 19:12:02 -070054 private Topology topology;
55 private TopologyDiscoveryInterface topologyDiscoveryInterface;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070056
Jonathan Hart88770672014-04-02 18:08:30 -070057 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
58 private boolean cleanupEnabled = true;
59 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
60 private SingletonTask cleanupTask;
Toshio Koide2f570c12014-02-06 16:55:32 -080061
Jonathan Hart369875b2014-02-13 10:00:31 -080062 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -070063 * Cleanup old switches from the topology. Old switches are those
Jonathan Hart88770672014-04-02 18:08:30 -070064 * which have no controller in the registry.
Jonathan Hart369875b2014-02-13 10:00:31 -080065 */
66 private class SwitchCleanup implements ControlChangeCallback, Runnable {
67 @Override
68 public void run() {
69 String old = Thread.currentThread().getName();
70 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -070071
Jonathan Hart369875b2014-02-13 10:00:31 -080072 try {
Jonathan Hart88770672014-04-02 18:08:30 -070073 if (log.isTraceEnabled()) {
74 log.trace("Running cleanup thread");
75 }
Jonathan Hart369875b2014-02-13 10:00:31 -080076 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -080077 } finally {
78 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -070079 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -080080 Thread.currentThread().setName(old);
81 }
82 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -070083
Jonathan Hart88770672014-04-02 18:08:30 -070084 /**
85 * First half of the switch cleanup operation. This method will attempt
86 * to get control of any switch it sees without a controller via the
87 * registry.
88 */
Jonathan Hart369875b2014-02-13 10:00:31 -080089 private void switchCleanup() {
Jonathan Harte37e4e22014-05-13 19:12:02 -070090 Iterable<Switch> switches = topology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -080091
Jonathan Hart88770672014-04-02 18:08:30 -070092 if (log.isTraceEnabled()) {
93 log.trace("Checking for inactive switches");
94 }
95 // For each switch check if a controller exists in controller registry
Ray Milkey269ffb92014-04-03 14:43:30 -070096 for (Switch sw : switches) {
Jonathan Hart88770672014-04-02 18:08:30 -070097 try {
98 String controller =
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -070099 registryService.getControllerForSwitch(sw.getDpid().value());
Jonathan Hart88770672014-04-02 18:08:30 -0700100 if (controller == null) {
101 log.debug("Requesting control to set switch {} INACTIVE",
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700102 sw.getDpid());
103 registryService.requestControl(sw.getDpid().value(), this);
Jonathan Hart88770672014-04-02 18:08:30 -0700104 }
105 } catch (RegistryException e) {
106 log.error("Caught RegistryException in cleanup thread", e);
107 }
108 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800109 }
110
Jonathan Hart88770672014-04-02 18:08:30 -0700111 /**
112 * Second half of the switch cleanup operation. If the registry grants
113 * control of a switch, we can be sure no other instance is writing
Jonathan Harte37e4e22014-05-13 19:12:02 -0700114 * this switch to the topology, so we can remove it now.
Ray Milkey269ffb92014-04-03 14:43:30 -0700115 *
116 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700117 * @param hasControl whether we got control or not
118 */
119 @Override
120 public void controlChanged(long dpid, boolean hasControl) {
121 if (hasControl) {
122 log.debug("Got control to set switch {} INACTIVE",
123 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700124
Jonathan Hart88770672014-04-02 18:08:30 -0700125 SwitchEvent switchEvent = new SwitchEvent(dpid);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700126 topologyDiscoveryInterface.
Jonathan Hart88770672014-04-02 18:08:30 -0700127 removeSwitchDiscoveryEvent(switchEvent);
128 registryService.releaseControl(dpid);
129 }
130 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800131 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800132
Jonathan Hart88770672014-04-02 18:08:30 -0700133 @Override
134 public void linkDiscoveryUpdate(LDUpdate update) {
Jonathan Hart121a0242014-06-06 15:53:42 -0700135
Jonathan Hart88770672014-04-02 18:08:30 -0700136 LinkEvent linkEvent = new LinkEvent(update.getSrc(),
137 (long) update.getSrcPort(), update.getDst(),
138 (long) update.getDstPort());
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700139
Jonathan Hart88770672014-04-02 18:08:30 -0700140 switch (update.getOperation()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 case LINK_ADDED:
Yuta HIGUCHIa00e4b92014-06-13 11:51:25 -0700142 if (!registryService.hasControl(update.getDst())) {
143 // Don't process or send a link event if we're not master for the
144 // destination switch
145 log.debug("Not the master for dst switch {}. Suppressed link add event {}.",
146 update.getDst(), linkEvent);
147 return;
148 }
Jonathan Harte37e4e22014-05-13 19:12:02 -0700149 topologyDiscoveryInterface.putLinkDiscoveryEvent(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700150 break;
151 case LINK_UPDATED:
152 // We don't use the LINK_UPDATED event (unsure what it means)
153 break;
154 case LINK_REMOVED:
Yuta HIGUCHIa00e4b92014-06-13 11:51:25 -0700155 if (!registryService.hasControl(update.getDst())) {
156 // Don't process or send a link event if we're not master for the
157 // destination switch
158 log.debug("Not the master for dst switch {}. Suppressed link remove event {}.",
159 update.getDst(), linkEvent);
160 return;
161 }
Jonathan Harte37e4e22014-05-13 19:12:02 -0700162 topologyDiscoveryInterface.removeLinkDiscoveryEvent(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700163 break;
164 default:
165 break;
Jonathan Hart88770672014-04-02 18:08:30 -0700166 }
167 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800168
Jonathan Hart88770672014-04-02 18:08:30 -0700169 @Override
170 public void switchPortAdded(Long switchId, OFPhysicalPort port) {
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700171
172 PortEvent portEvent = new PortEvent(switchId, (long) port.getPortNumber());
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700173 if (registryService.hasControl(switchId)) {
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700174 topologyDiscoveryInterface.putPortDiscoveryEvent(portEvent);
175 linkDiscovery.removeFromSuppressLLDPs(switchId, port.getPortNumber());
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700176 } else {
177 log.debug("Not the master for switch {}. Suppressed port add event {}.",
178 new Dpid(switchId), portEvent);
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700179 }
Jonathan Hart88770672014-04-02 18:08:30 -0700180 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800181
Jonathan Hart88770672014-04-02 18:08:30 -0700182 @Override
183 public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700184
185 PortEvent portEvent = new PortEvent(switchId, (long) port.getPortNumber());
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700186 if (registryService.hasControl(switchId)) {
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700187 topologyDiscoveryInterface.removePortDiscoveryEvent(portEvent);
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700188 } else {
189 log.debug("Not the master for switch {}. Suppressed port del event {}.",
190 new Dpid(switchId), portEvent);
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700191 }
Jonathan Hart88770672014-04-02 18:08:30 -0700192 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800193
Jonathan Hart88770672014-04-02 18:08:30 -0700194 @Override
195 public void addedSwitch(IOFSwitch sw) {
Toshio Koide2f570c12014-02-06 16:55:32 -0800196
Jonathan Hart88770672014-04-02 18:08:30 -0700197 SwitchEvent switchEvent = new SwitchEvent(sw.getId());
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700198
Yuta HIGUCHI5bbbaca2014-06-09 16:39:08 -0700199 // TODO Not very robust
200 if (!registryService.hasControl(sw.getId())) {
201 log.debug("Not the master for switch {}. Suppressed switch add event {}.",
202 new Dpid(sw.getId()), switchEvent);
203 return;
204 }
205
Jonathan Hart88770672014-04-02 18:08:30 -0700206 List<PortEvent> portEvents = new ArrayList<PortEvent>();
207 for (OFPhysicalPort port : sw.getPorts()) {
208 portEvents.add(new PortEvent(sw.getId(), (long) port.getPortNumber()));
209 }
Jonathan Harte37e4e22014-05-13 19:12:02 -0700210 topologyDiscoveryInterface
Ray Milkey269ffb92014-04-03 14:43:30 -0700211 .putSwitchDiscoveryEvent(switchEvent, portEvents);
Toshio Koide2f570c12014-02-06 16:55:32 -0800212
Jonathan Hart88770672014-04-02 18:08:30 -0700213 for (OFPhysicalPort port : sw.getPorts()) {
214 // Allow links to be discovered on this port now that it's
215 // in the database
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700216 linkDiscovery.removeFromSuppressLLDPs(sw.getId(), port.getPortNumber());
Jonathan Hart88770672014-04-02 18:08:30 -0700217 }
218 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800219
Jonathan Hart88770672014-04-02 18:08:30 -0700220 @Override
221 public void removedSwitch(IOFSwitch sw) {
222 // We don't use this event - switch remove is done by cleanup thread
223 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800224
Jonathan Hart88770672014-04-02 18:08:30 -0700225 @Override
226 public void switchPortChanged(Long switchId) {
227 // We don't use this event
228 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800229
Jonathan Hart88770672014-04-02 18:08:30 -0700230 @Override
231 public String getName() {
232 // TODO Auto-generated method stub
233 return null;
234 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800235
Jonathan Hart88770672014-04-02 18:08:30 -0700236 /* *****************
237 * IFloodlightModule
238 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800239
Jonathan Hart88770672014-04-02 18:08:30 -0700240 @Override
241 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
242 return null;
243 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800244
Jonathan Hart88770672014-04-02 18:08:30 -0700245 @Override
246 public Map<Class<? extends IFloodlightService>, IFloodlightService>
247 getServiceImpls() {
248 return null;
249 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800250
Jonathan Hart88770672014-04-02 18:08:30 -0700251 @Override
252 public Collection<Class<? extends IFloodlightService>>
Ray Milkey269ffb92014-04-03 14:43:30 -0700253 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700254 Collection<Class<? extends IFloodlightService>> l =
255 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800256 l.add(IFloodlightProviderService.class);
257 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800258 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800259 l.add(IControllerRegistryService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700260 l.add(ITopologyService.class);
Jonathan Hartebbe6a62014-04-02 16:10:25 -0700261 l.add(IOnosDeviceService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800262 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700263 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800264
Jonathan Hart88770672014-04-02 18:08:30 -0700265 @Override
266 public void init(FloodlightModuleContext context)
267 throws FloodlightModuleException {
268 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
269 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
270 registryService = context.getServiceImpl(IControllerRegistryService.class);
271 onosDeviceService = context.getServiceImpl(IOnosDeviceService.class);
Toshio Koide2f570c12014-02-06 16:55:32 -0800272
Jonathan Harte37e4e22014-05-13 19:12:02 -0700273 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700274 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800275
Jonathan Hart88770672014-04-02 18:08:30 -0700276 @Override
277 public void startUp(FloodlightModuleContext context) {
278 floodlightProvider.addOFSwitchListener(this);
279 linkDiscovery.addListener(this);
280 onosDeviceService.addOnosDeviceListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800281
Jonathan Harte37e4e22014-05-13 19:12:02 -0700282 topology = topologyService.getTopology();
283 topologyDiscoveryInterface =
284 topologyService.getTopologyDiscoveryInterface();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700285
Jonathan Hart88770672014-04-02 18:08:30 -0700286 // Run the cleanup thread
287 String enableCleanup =
288 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
289 if (enableCleanup != null
290 && enableCleanup.equalsIgnoreCase("false")) {
291 cleanupEnabled = false;
292 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700293
Jonathan Hart88770672014-04-02 18:08:30 -0700294 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700295
Jonathan Hart88770672014-04-02 18:08:30 -0700296 if (cleanupEnabled) {
297 IThreadPoolService threadPool =
298 context.getServiceImpl(IThreadPoolService.class);
299 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
300 new SwitchCleanup());
301 // Run the cleanup task immediately on startup
302 cleanupTask.reschedule(0, TimeUnit.SECONDS);
303 }
304 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700305
Jonathan Hart88770672014-04-02 18:08:30 -0700306 @Override
307 public void onosDeviceAdded(OnosDevice device) {
308 log.debug("Called onosDeviceAdded mac {}", device.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700309
TeruU5d2c9392014-06-09 20:02:02 -0700310 SwitchPort sp = new SwitchPort(device.getSwitchDPID(), device.getSwitchPort());
Jonathan Hart88770672014-04-02 18:08:30 -0700311 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
312 spLists.add(sp);
313 DeviceEvent event = new DeviceEvent(device.getMacAddress());
314 event.setAttachmentPoints(spLists);
315 event.setLastSeenTime(device.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700316 // Does not use vlan info now.
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700317
Jonathan Harte37e4e22014-05-13 19:12:02 -0700318 topologyDiscoveryInterface.putDeviceDiscoveryEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700319 }
TeruUd1c5b652014-03-24 13:58:46 -0700320
Jonathan Hart88770672014-04-02 18:08:30 -0700321 @Override
322 public void onosDeviceRemoved(OnosDevice device) {
323 log.debug("Called onosDeviceRemoved");
324 DeviceEvent event = new DeviceEvent(device.getMacAddress());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700325 topologyDiscoveryInterface.removeDeviceDiscoveryEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700326 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800327}