blob: 37e71c90e3a0b1e1d70463d30436ad63a239d05b [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) {
Jonathan Hart121a0242014-06-06 15:53:42 -0700134 if (!registryService.hasControl(update.getDst())) {
135 // Don't process or send a link event if we're not master for the
136 // destination switch
137 return;
138 }
139
Jonathan Hart88770672014-04-02 18:08:30 -0700140 LinkEvent linkEvent = new LinkEvent(update.getSrc(),
141 (long) update.getSrcPort(), update.getDst(),
142 (long) update.getDstPort());
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700143
Jonathan Hart88770672014-04-02 18:08:30 -0700144 switch (update.getOperation()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700145 case LINK_ADDED:
Jonathan Harte37e4e22014-05-13 19:12:02 -0700146 topologyDiscoveryInterface.putLinkDiscoveryEvent(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700147 break;
148 case LINK_UPDATED:
149 // We don't use the LINK_UPDATED event (unsure what it means)
150 break;
151 case LINK_REMOVED:
Jonathan Harte37e4e22014-05-13 19:12:02 -0700152 topologyDiscoveryInterface.removeLinkDiscoveryEvent(linkEvent);
Ray Milkey269ffb92014-04-03 14:43:30 -0700153 break;
154 default:
155 break;
Jonathan Hart88770672014-04-02 18:08:30 -0700156 }
157 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800158
Jonathan Hart88770672014-04-02 18:08:30 -0700159 @Override
160 public void switchPortAdded(Long switchId, OFPhysicalPort port) {
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700161 if (registryService.hasControl(switchId)) {
162 PortEvent portEvent = new PortEvent(switchId, (long) port.getPortNumber());
163 topologyDiscoveryInterface.putPortDiscoveryEvent(portEvent);
164 linkDiscovery.removeFromSuppressLLDPs(switchId, port.getPortNumber());
165 }
Jonathan Hart88770672014-04-02 18:08:30 -0700166 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800167
Jonathan Hart88770672014-04-02 18:08:30 -0700168 @Override
169 public void switchPortRemoved(Long switchId, OFPhysicalPort port) {
Jonathan Hart67b6cba2014-05-30 22:36:37 -0700170 if (registryService.hasControl(switchId)) {
171 PortEvent portEvent = new PortEvent(switchId, (long) port.getPortNumber());
172 topologyDiscoveryInterface.removePortDiscoveryEvent(portEvent);
173 }
Jonathan Hart88770672014-04-02 18:08:30 -0700174 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800175
Jonathan Hart88770672014-04-02 18:08:30 -0700176 @Override
177 public void addedSwitch(IOFSwitch sw) {
178 // TODO Not very robust
179 if (!registryService.hasControl(sw.getId())) {
180 return;
181 }
Toshio Koide2f570c12014-02-06 16:55:32 -0800182
Jonathan Hart88770672014-04-02 18:08:30 -0700183 SwitchEvent switchEvent = new SwitchEvent(sw.getId());
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700184
Jonathan Hart88770672014-04-02 18:08:30 -0700185 List<PortEvent> portEvents = new ArrayList<PortEvent>();
186 for (OFPhysicalPort port : sw.getPorts()) {
187 portEvents.add(new PortEvent(sw.getId(), (long) port.getPortNumber()));
188 }
Jonathan Harte37e4e22014-05-13 19:12:02 -0700189 topologyDiscoveryInterface
Ray Milkey269ffb92014-04-03 14:43:30 -0700190 .putSwitchDiscoveryEvent(switchEvent, portEvents);
Toshio Koide2f570c12014-02-06 16:55:32 -0800191
Jonathan Hart88770672014-04-02 18:08:30 -0700192 for (OFPhysicalPort port : sw.getPorts()) {
193 // Allow links to be discovered on this port now that it's
194 // in the database
Pavlin Radoslavov7d21c0a2014-04-10 10:32:59 -0700195 linkDiscovery.removeFromSuppressLLDPs(sw.getId(), port.getPortNumber());
Jonathan Hart88770672014-04-02 18:08:30 -0700196 }
197 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800198
Jonathan Hart88770672014-04-02 18:08:30 -0700199 @Override
200 public void removedSwitch(IOFSwitch sw) {
201 // We don't use this event - switch remove is done by cleanup thread
202 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800203
Jonathan Hart88770672014-04-02 18:08:30 -0700204 @Override
205 public void switchPortChanged(Long switchId) {
206 // We don't use this event
207 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800208
Jonathan Hart88770672014-04-02 18:08:30 -0700209 @Override
210 public String getName() {
211 // TODO Auto-generated method stub
212 return null;
213 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800214
Jonathan Hart88770672014-04-02 18:08:30 -0700215 /* *****************
216 * IFloodlightModule
217 * *****************/
Toshio Koide2f570c12014-02-06 16:55:32 -0800218
Jonathan Hart88770672014-04-02 18:08:30 -0700219 @Override
220 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
221 return null;
222 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800223
Jonathan Hart88770672014-04-02 18:08:30 -0700224 @Override
225 public Map<Class<? extends IFloodlightService>, IFloodlightService>
226 getServiceImpls() {
227 return null;
228 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800229
Jonathan Hart88770672014-04-02 18:08:30 -0700230 @Override
231 public Collection<Class<? extends IFloodlightService>>
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 getModuleDependencies() {
Jonathan Hart88770672014-04-02 18:08:30 -0700233 Collection<Class<? extends IFloodlightService>> l =
234 new ArrayList<Class<? extends IFloodlightService>>();
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800235 l.add(IFloodlightProviderService.class);
236 l.add(ILinkDiscoveryService.class);
Jonathan Hart369875b2014-02-13 10:00:31 -0800237 l.add(IThreadPoolService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800238 l.add(IControllerRegistryService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700239 l.add(ITopologyService.class);
Jonathan Hartebbe6a62014-04-02 16:10:25 -0700240 l.add(IOnosDeviceService.class);
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800241 return l;
Jonathan Hart88770672014-04-02 18:08:30 -0700242 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800243
Jonathan Hart88770672014-04-02 18:08:30 -0700244 @Override
245 public void init(FloodlightModuleContext context)
246 throws FloodlightModuleException {
247 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
248 linkDiscovery = context.getServiceImpl(ILinkDiscoveryService.class);
249 registryService = context.getServiceImpl(IControllerRegistryService.class);
250 onosDeviceService = context.getServiceImpl(IOnosDeviceService.class);
Toshio Koide2f570c12014-02-06 16:55:32 -0800251
Jonathan Harte37e4e22014-05-13 19:12:02 -0700252 topologyService = context.getServiceImpl(ITopologyService.class);
Jonathan Hart88770672014-04-02 18:08:30 -0700253 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800254
Jonathan Hart88770672014-04-02 18:08:30 -0700255 @Override
256 public void startUp(FloodlightModuleContext context) {
257 floodlightProvider.addOFSwitchListener(this);
258 linkDiscovery.addListener(this);
259 onosDeviceService.addOnosDeviceListener(this);
Toshio Koide2f570c12014-02-06 16:55:32 -0800260
Jonathan Harte37e4e22014-05-13 19:12:02 -0700261 topology = topologyService.getTopology();
262 topologyDiscoveryInterface =
263 topologyService.getTopologyDiscoveryInterface();
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700264
Jonathan Hart88770672014-04-02 18:08:30 -0700265 // Run the cleanup thread
266 String enableCleanup =
267 context.getConfigParams(this).get(ENABLE_CLEANUP_PROPERTY);
268 if (enableCleanup != null
269 && enableCleanup.equalsIgnoreCase("false")) {
270 cleanupEnabled = false;
271 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700272
Jonathan Hart88770672014-04-02 18:08:30 -0700273 log.debug("Cleanup thread is {}enabled", (cleanupEnabled) ? "" : "not ");
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700274
Jonathan Hart88770672014-04-02 18:08:30 -0700275 if (cleanupEnabled) {
276 IThreadPoolService threadPool =
277 context.getServiceImpl(IThreadPoolService.class);
278 cleanupTask = new SingletonTask(threadPool.getScheduledExecutor(),
279 new SwitchCleanup());
280 // Run the cleanup task immediately on startup
281 cleanupTask.reschedule(0, TimeUnit.SECONDS);
282 }
283 }
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700284
Jonathan Hart88770672014-04-02 18:08:30 -0700285 @Override
286 public void onosDeviceAdded(OnosDevice device) {
287 log.debug("Called onosDeviceAdded mac {}", device.getMacAddress());
TeruUd1c5b652014-03-24 13:58:46 -0700288
Jonathan Hart88770672014-04-02 18:08:30 -0700289 SwitchPort sp = new SwitchPort(device.getSwitchDPID(),
290 (long) device.getSwitchPort());
291 List<SwitchPort> spLists = new ArrayList<SwitchPort>();
292 spLists.add(sp);
293 DeviceEvent event = new DeviceEvent(device.getMacAddress());
294 event.setAttachmentPoints(spLists);
295 event.setLastSeenTime(device.getLastSeenTimestamp().getTime());
Jonathan Hart88770672014-04-02 18:08:30 -0700296 // Does not use vlan info now.
Jonathan Hartb3e1b052014-04-02 16:01:12 -0700297
Jonathan Harte37e4e22014-05-13 19:12:02 -0700298 topologyDiscoveryInterface.putDeviceDiscoveryEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700299 }
TeruUd1c5b652014-03-24 13:58:46 -0700300
Jonathan Hart88770672014-04-02 18:08:30 -0700301 @Override
302 public void onosDeviceRemoved(OnosDevice device) {
303 log.debug("Called onosDeviceRemoved");
304 DeviceEvent event = new DeviceEvent(device.getMacAddress());
Jonathan Harte37e4e22014-05-13 19:12:02 -0700305 topologyDiscoveryInterface.removeDeviceDiscoveryEvent(event);
Jonathan Hart88770672014-04-02 18:08:30 -0700306 }
Jonathan Hart4b5bbb52014-02-06 10:09:31 -0800307}