blob: 904ca3f9b87f140b1dfb1dce313af357c49dea16 [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;
Jonathan Hart472062d2014-04-03 10:56:48 -070026import net.onrc.onos.core.topology.PortEvent.SwitchPort;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080027
28import org.openflow.protocol.OFPhysicalPort;
Jonathan Hart369875b2014-02-13 10:00:31 -080029import org.openflow.util.HexString;
Toshio Koide2f570c12014-02-06 16:55:32 -080030import org.slf4j.Logger;
31import org.slf4j.LoggerFactory;
Jonathan Hart4b5bbb52014-02-06 10:09:31 -080032
Jonathan Hart88770672014-04-02 18:08:30 -070033/**
Jonathan Harte37e4e22014-05-13 19:12:02 -070034 * The TopologyPublisher subscribes to topology network events from the
35 * discovery modules. These events are reformatted and relayed to the in-memory
36 * topology instance.
Jonathan Hart88770672014-04-02 18:08:30 -070037 */
Jonathan Harte37e4e22014-05-13 19:12:02 -070038public class TopologyPublisher implements /*IOFSwitchListener,*/
Ray Milkey269ffb92014-04-03 14:43:30 -070039 IOFSwitchPortListener,
40 ILinkDiscoveryListener,
41 IFloodlightModule,
42 IOnosDeviceListener {
Jonathan Hart88770672014-04-02 18:08:30 -070043 private static final Logger log =
Jonathan Harte37e4e22014-05-13 19:12:02 -070044 LoggerFactory.getLogger(TopologyPublisher.class);
Yuta HIGUCHIcb951982014-02-11 13:31:44 -080045
Jonathan Hart88770672014-04-02 18:08:30 -070046 private IFloodlightProviderService floodlightProvider;
47 private ILinkDiscoveryService linkDiscovery;
48 private IControllerRegistryService registryService;
Jonathan Harte37e4e22014-05-13 19:12:02 -070049 private ITopologyService topologyService;
Toshio Koide2f570c12014-02-06 16:55:32 -080050
Jonathan Hart88770672014-04-02 18:08:30 -070051 private IOnosDeviceService onosDeviceService;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070052
Jonathan Harte37e4e22014-05-13 19:12:02 -070053 private Topology topology;
54 private TopologyDiscoveryInterface topologyDiscoveryInterface;
Jonathan Hartb3e1b052014-04-02 16:01:12 -070055
Jonathan Hart88770672014-04-02 18:08:30 -070056 private static final String ENABLE_CLEANUP_PROPERTY = "EnableCleanup";
57 private boolean cleanupEnabled = true;
58 private static final int CLEANUP_TASK_INTERVAL = 60; // in seconds
59 private SingletonTask cleanupTask;
Toshio Koide2f570c12014-02-06 16:55:32 -080060
Jonathan Hart369875b2014-02-13 10:00:31 -080061 /**
Jonathan Harte37e4e22014-05-13 19:12:02 -070062 * Cleanup old switches from the topology. Old switches are those
Jonathan Hart88770672014-04-02 18:08:30 -070063 * which have no controller in the registry.
Jonathan Hart369875b2014-02-13 10:00:31 -080064 */
65 private class SwitchCleanup implements ControlChangeCallback, Runnable {
66 @Override
67 public void run() {
68 String old = Thread.currentThread().getName();
69 Thread.currentThread().setName("SwitchCleanup@" + old);
Jonathan Hartb3e1b052014-04-02 16:01:12 -070070
Jonathan Hart369875b2014-02-13 10:00:31 -080071 try {
Jonathan Hart88770672014-04-02 18:08:30 -070072 if (log.isTraceEnabled()) {
73 log.trace("Running cleanup thread");
74 }
Jonathan Hart369875b2014-02-13 10:00:31 -080075 switchCleanup();
Jonathan Hart369875b2014-02-13 10:00:31 -080076 } finally {
77 cleanupTask.reschedule(CLEANUP_TASK_INTERVAL,
Jonathan Hart88770672014-04-02 18:08:30 -070078 TimeUnit.SECONDS);
Jonathan Hart369875b2014-02-13 10:00:31 -080079 Thread.currentThread().setName(old);
80 }
81 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -070082
Jonathan Hart88770672014-04-02 18:08:30 -070083 /**
84 * First half of the switch cleanup operation. This method will attempt
85 * to get control of any switch it sees without a controller via the
86 * registry.
87 */
Jonathan Hart369875b2014-02-13 10:00:31 -080088 private void switchCleanup() {
Jonathan Harte37e4e22014-05-13 19:12:02 -070089 Iterable<Switch> switches = topology.getSwitches();
Jonathan Hart369875b2014-02-13 10:00:31 -080090
Jonathan Hart88770672014-04-02 18:08:30 -070091 if (log.isTraceEnabled()) {
92 log.trace("Checking for inactive switches");
93 }
94 // For each switch check if a controller exists in controller registry
Ray Milkey269ffb92014-04-03 14:43:30 -070095 for (Switch sw : switches) {
Jonathan Hart88770672014-04-02 18:08:30 -070096 try {
97 String controller =
98 registryService.getControllerForSwitch(sw.getDpid());
99 if (controller == null) {
100 log.debug("Requesting control to set switch {} INACTIVE",
101 HexString.toHexString(sw.getDpid()));
102 registryService.requestControl(sw.getDpid(), this);
103 }
104 } catch (RegistryException e) {
105 log.error("Caught RegistryException in cleanup thread", e);
106 }
107 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800108 }
109
Jonathan Hart88770672014-04-02 18:08:30 -0700110 /**
111 * Second half of the switch cleanup operation. If the registry grants
112 * control of a switch, we can be sure no other instance is writing
Jonathan Harte37e4e22014-05-13 19:12:02 -0700113 * this switch to the topology, so we can remove it now.
Ray Milkey269ffb92014-04-03 14:43:30 -0700114 *
115 * @param dpid the dpid of the switch we requested control for
Jonathan Hart88770672014-04-02 18:08:30 -0700116 * @param hasControl whether we got control or not
117 */
118 @Override
119 public void controlChanged(long dpid, boolean hasControl) {
120 if (hasControl) {
121 log.debug("Got control to set switch {} INACTIVE",
122 HexString.toHexString(dpid));
Jonathan Harte02cf542014-04-02 16:24:44 -0700123
Jonathan Hart88770672014-04-02 18:08:30 -0700124 SwitchEvent switchEvent = new SwitchEvent(dpid);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700125 topologyDiscoveryInterface.
Jonathan Hart88770672014-04-02 18:08:30 -0700126 removeSwitchDiscoveryEvent(switchEvent);
127 registryService.releaseControl(dpid);
128 }
129 }
Jonathan Hart369875b2014-02-13 10:00:31 -0800130 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800131
Jonathan Hart88770672014-04-02 18:08:30 -0700132 @Override
133 public void linkDiscoveryUpdate(LDUpdate update) {
134 LinkEvent linkEvent = new LinkEvent(update.getSrc(),
135 (long) update.getSrcPort(), update.getDst(),
136 (long) update.getDstPort());
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700137
Jonathan Hart88770672014-04-02 18:08:30 -0700138 switch (update.getOperation()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700139 case LINK_ADDED:
Jonathan Harte37e4e22014-05-13 19:12:02 -0700140 topologyDiscoveryInterface.putLinkDiscoveryEvent(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700141 break;
142 case LINK_UPDATED:
143 // We don't use the LINK_UPDATED event (unsure what it means)
144 break;
145 case LINK_REMOVED:
Jonathan Harte37e4e22014-05-13 19:12:02 -0700146 topologyDiscoveryInterface.removeLinkDiscoveryEvent(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 break;
148 default:
149 break;
Jonathan Hart88770672014-04-02 18:08:30 -0700150 }
151 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800152
Jonathan Hart88770672014-04-02 18:08:30 -0700153 @Override
154 public void switchPortAdded(Long switchId, OFPhysicalPort port) {
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700155 if (registryService.hasControl(switchId)) {
156 PortEvent portEvent = new PortEvent(switchId, (long) port.getPortNumber());
157 topologyDiscoveryInterface.putPortDiscoveryEvent(portEvent);
158 linkDiscovery.removeFromSuppressLLDPs(switchId, port.getPortNumber());
159 }
Jonathan Hart88770672014-04-02 18:08:30 -0700160 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800161
Jonathan Hart88770672014-04-02 18:08:30 -0700162 @Override
163 public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700164 if (registryService.hasControl(switchId)) {
165 PortEvent portEvent = new PortEvent(switchId, (long) port.getPortNumber());
166 topologyDiscoveryInterface.removePortDiscoveryEvent(portEvent);
167 }
Jonathan Hart88770672014-04-02 18:08:30 -0700168 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800169
Jonathan Hart88770672014-04-02 18:08:30 -0700170 @Override
171 public void addedSwitch(IOFSwitch sw) {
172 // TODO Not very robust
173 if (!registryService.hasControl(sw.getId())) {
174 return;
175 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800176
Jonathan Hart88770672014-04-02 18:08:30 -0700177 SwitchEvent switchEvent = new SwitchEvent(sw.getId());
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700178
Jonathan Hart88770672014-04-02 18:08:30 -0700179 List<PortEvent> portEvents = new ArrayList<PortEvent>();
180 for (OFPhysicalPort port : sw.getPorts()) {
181 portEvents.add(new PortEvent(sw.getId(), (long) port.getPortNumber()));
182 }
Jonathan Harte37e4e22014-05-13 19:12:02 -0700183 topologyDiscoveryInterface
Ray Milkey269ffb92014-04-03 14:43:30 -0700184 .putSwitchDiscoveryEvent(switchEvent, portEvents);
Toshio Koide2f570c12014-02-06 16:55:32 -0800185
Jonathan Hart88770672014-04-02 18:08:30 -0700186 for (OFPhysicalPort port : sw.getPorts()) {
187 // Allow links to be discovered on this port now that it's
188 // in the database
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700189 linkDiscovery.removeFromSuppressLLDPs(sw.getId(), port.getPortNumber());
Jonathan Hart88770672014-04-02 18:08:30 -0700190 }
191 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800192
Jonathan Hart88770672014-04-02 18:08:30 -0700193 @Override
194 public void removedSwitch(IOFSwitch sw) {
195 // We don't use this event - switch remove is done by cleanup thread
196 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800197
Jonathan Hart88770672014-04-02 18:08:30 -0700198 @Override
199 public void switchPortChanged(Long switchId) {
200 // We don't use this event
201 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800202
Jonathan Hart88770672014-04-02 18:08:30 -0700203 @Override
204 public String getName() {
205 // TODO Auto-generated method stub
206 return null;
207 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800208
Jonathan Hart88770672014-04-02 18:08:30 -0700209 /* *****************
210 * IFloodlightModule
211 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800212
Jonathan Hart88770672014-04-02 18:08:30 -0700213 @Override
214 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
215 return null;
216 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800217
Jonathan Hart88770672014-04-02 18:08:30 -0700218 @Override
219 public Map<Class<? extends IFloodlightService>, IFloodlightService>
220 getServiceImpls() {
221 return null;
222 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800223
Jonathan Hart88770672014-04-02 18:08:30 -0700224 @Override
225 public Collection<Class<? extends IFloodlightService>>
Ray Milkey269ffb92014-04-03 14:43:30 -0700226 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700227 Collection<Class<? extends IFloodlightService>> l =
228 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800229 l.add(IFloodlightProviderService.class);
230 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800231 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800232 l.add(IControllerRegistryService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700233 l.add(ITopologyService.class);
Jonathan Hartebbe6a62014-04-02 16:10:25 -0700234 l.add(IOnosDeviceService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800235 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700236 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800237
Jonathan Hart88770672014-04-02 18:08:30 -0700238 @Override
239 public void init(FloodlightModuleContext context)
240 throws FloodlightModuleException {
241 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
242 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
243 registryService = context.getServiceImpl(IControllerRegistryService.class);
244 onosDeviceService = context.getServiceImpl(IOnosDeviceService.class);
Toshio Koide2f570c12014-02-06 16:55:32 -0800245
Jonathan Harte37e4e22014-05-13 19:12:02 -0700246 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700247 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800248
Jonathan Hart88770672014-04-02 18:08:30 -0700249 @Override
250 public void startUp(FloodlightModuleContext context) {
251 floodlightProvider.addOFSwitchListener(this);
252 linkDiscovery.addListener(this);
253 onosDeviceService.addOnosDeviceListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800254
Jonathan Harte37e4e22014-05-13 19:12:02 -0700255 topology = topologyService.getTopology();
256 topologyDiscoveryInterface =
257 topologyService.getTopologyDiscoveryInterface();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700258
Jonathan Hart88770672014-04-02 18:08:30 -0700259 // Run the cleanup thread
260 String enableCleanup =
261 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
262 if (enableCleanup != null
263 && enableCleanup.equalsIgnoreCase("false")) {
264 cleanupEnabled = false;
265 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700266
Jonathan Hart88770672014-04-02 18:08:30 -0700267 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700268
Jonathan Hart88770672014-04-02 18:08:30 -0700269 if (cleanupEnabled) {
270 IThreadPoolService threadPool =
271 context.getServiceImpl(IThreadPoolService.class);
272 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
273 new SwitchCleanup());
274 // Run the cleanup task immediately on startup
275 cleanupTask.reschedule(0, TimeUnit.SECONDS);
276 }
277 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700278
Jonathan Hart88770672014-04-02 18:08:30 -0700279 @Override
280 public void onosDeviceAdded(OnosDevice device) {
281 log.debug("Called onosDeviceAdded mac {}", device.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700282
Jonathan Hart88770672014-04-02 18:08:30 -0700283 SwitchPort sp = new SwitchPort(device.getSwitchDPID(),
284 (long) device.getSwitchPort());
285 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
286 spLists.add(sp);
287 DeviceEvent event = new DeviceEvent(device.getMacAddress());
288 event.setAttachmentPoints(spLists);
289 event.setLastSeenTime(device.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700290 // Does not use vlan info now.
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700291
Jonathan Harte37e4e22014-05-13 19:12:02 -0700292 topologyDiscoveryInterface.putDeviceDiscoveryEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700293 }
TeruUd1c5b652014-03-24 13:58:46 -0700294
Jonathan Hart88770672014-04-02 18:08:30 -0700295 @Override
296 public void onosDeviceRemoved(OnosDevice device) {
297 log.debug("Called onosDeviceRemoved");
298 DeviceEvent event = new DeviceEvent(device.getMacAddress());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700299 topologyDiscoveryInterface.removeDeviceDiscoveryEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700300 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800301}